org.datafx.controller.flow.FlowHandler Maven / Gradle / Ivy
/**
* Copyright (c) 2011, 2013, Jonathan Giles, Johan Vos, Hendrik Ebbers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of DataFX, the website javafxdata.org, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.datafx.controller.flow;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.layout.StackPane;
import org.datafx.controller.FxmlLoadException;
import org.datafx.controller.ViewConfiguration;
import org.datafx.controller.ViewFactory;
import org.datafx.controller.context.ViewContext;
import org.datafx.controller.context.ViewMetadata;
import org.datafx.controller.flow.action.FlowAction;
import org.datafx.controller.flow.action.FlowLink;
import org.datafx.controller.flow.context.FlowActionHandler;
import org.datafx.controller.flow.context.ViewFlowContext;
import org.datafx.controller.flow.event.*;
import org.datafx.controller.util.Veto;
import org.datafx.controller.util.VetoException;
import org.datafx.controller.util.VetoHandler;
import org.datafx.util.ExceptionHandler;
import java.util.ResourceBundle;
import java.util.UUID;
public class FlowHandler {
private final ObservableList> controllerHistory;
private ReadOnlyObjectWrapper> currentViewWrapper;
private ReadOnlyObjectWrapper containerWrapper;
private ReadOnlyObjectWrapper flowContextWrapper;
private ReadOnlyObjectWrapper flowWrapper;
private SimpleObjectProperty beforeFlowActionHandler;
private SimpleObjectProperty afterFlowActionHandler;
private SimpleObjectProperty vetoableBeforeFlowActionHandler;
private SimpleObjectProperty vetoHandler;
private ViewConfiguration viewConfiguration;
private ExceptionHandler exceptionHandler;
private ReadOnlyObjectWrapper currentViewMetadataWrapper;
public FlowHandler(Flow flow, ViewFlowContext flowContext) {
this(flow, flowContext, new ViewConfiguration());
}
public FlowHandler(Flow flow, ViewFlowContext flowContext, ViewConfiguration viewConfiguration) {
this(flow, flowContext, viewConfiguration, ExceptionHandler.getDefaultInstance());
}
public FlowHandler(Flow flow, ViewFlowContext flowContext, ViewConfiguration viewConfiguration, ExceptionHandler exceptionHandler) {
this.flowWrapper = new ReadOnlyObjectWrapper<>(flow);
this.viewConfiguration = viewConfiguration;
this.exceptionHandler = exceptionHandler;
controllerHistory = FXCollections.observableArrayList();
currentViewWrapper = new ReadOnlyObjectWrapper<>();
containerWrapper = new ReadOnlyObjectWrapper<>();
flowContextWrapper = new ReadOnlyObjectWrapper<>(flowContext);
currentViewMetadataWrapper = new ReadOnlyObjectWrapper<>();
flowContextWrapper.get().currentViewContextProperty().addListener((e) -> currentViewMetadataWrapper.set(flowContextWrapper.get().getCurrentViewContext().getMetadata()));
flowContextWrapper.get().register(new FlowActionHandler(this));
}
public StackPane start() throws FlowException {
return start(new DefaultFlowContainer());
}
public Tab startInTab() throws FlowException {
return startInTab(new DefaultFlowContainer());
}
public Tab startInTab(FlowContainer container) throws FlowException {
Tab tab = new Tab();
getCurrentViewMetadata().addListener((e) -> {
tab.textProperty().unbind();
tab.graphicProperty().unbind();
tab.textProperty().bind(getCurrentViewMetadata().get().titleProperty());
tab.graphicProperty().bind(getCurrentViewMetadata().get().graphicsProperty());
});
tab.setOnClosed(e -> {
try {
destroy();
} catch (Exception exception) {
exceptionHandler.setException(exception);
}
});
tab.setContent(start(container));
return tab;
}
public void destroy() {
//TODO
}
public T start(FlowContainer container) throws FlowException {
containerWrapper.set(container);
flowContextWrapper.get().register(this);
if (viewConfiguration != null) {
flowContextWrapper.get().register(ResourceBundle.class.toString(), viewConfiguration.getResources());
}
try {
FlowView> startView = new FlowView(ViewFactory.getInstance().createByController(flowWrapper.get().getStartViewControllerClass(), null, getViewConfiguration(), flowContextWrapper.get()));
setNewView(startView);
} catch (FxmlLoadException e) {
throw new FlowException(e);
}
return container.getView();
}
public ViewConfiguration getViewConfiguration() {
return viewConfiguration;
}
public void handle(String actionId) throws VetoException, FlowException {
FlowAction action = null;
if (getCurrentView() != null) {
action = getCurrentView().getActionById(actionId);
}
if (action == null) {
action = flowWrapper.get().getGlobalActionById(actionId);
}
handle(action, actionId);
}
public ExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
public ViewFlowContext getFlowContext() {
return flowContextWrapper.get();
}
public ReadOnlyObjectProperty getCurrentViewMetadata() {
return currentViewMetadataWrapper.getReadOnlyProperty();
}
public ReadOnlyObjectProperty getFlowContextProperty() {
return flowContextWrapper.getReadOnlyProperty();
}
public ReadOnlyObjectProperty> getCurrentViewProperty() {
return currentViewWrapper.getReadOnlyProperty();
}
public ReadOnlyObjectProperty getContainerProperty() {
return containerWrapper.getReadOnlyProperty();
}
public FlowView> getCurrentView() {
return currentViewWrapper.get();
}
public ViewContext> getCurrentViewContext() {
return getCurrentView().getViewContext();
}
public void handle(FlowAction action, String actionId) throws FlowException, VetoException {
if (beforeFlowActionHandler != null && beforeFlowActionHandler.getValue() != null) {
beforeFlowActionHandler.getValue().handle(new BeforeFlowActionEvent(actionId, action, flowContextWrapper.get()));
}
if (vetoableBeforeFlowActionHandler != null && vetoableBeforeFlowActionHandler.getValue() != null) {
try {
vetoableBeforeFlowActionHandler.getValue().handle(new BeforeFlowActionEvent(actionId, action, flowContextWrapper.get()));
} catch (Veto veto) {
if (vetoHandler != null && vetoHandler.getValue() != null) {
vetoHandler.get().onVeto(veto);
}
throw new VetoException(veto);
}
}
action.handle(this, actionId);
if (afterFlowActionHandler != null && afterFlowActionHandler.getValue() != null) {
afterFlowActionHandler.getValue().handle(new AfterFlowActionEvent(actionId, action, flowContextWrapper.get()));
}
}
public ViewContext setNewView(FlowView newView)
throws FlowException {
if (getCurrentView() != null) {
ViewHistoryDefinition> historyDefinition = new ViewHistoryDefinition(getCurrentView().getViewContext().getController().getClass(), "", null);
controllerHistory.add(0, historyDefinition);
}
flowWrapper.get().addActionsToView(newView);
FlowView> oldView = getCurrentView();
if (oldView != null) {
ViewContext> lastViewContext = oldView.getViewContext();
if (lastViewContext != null) {
try {
lastViewContext.destroy();
} catch (Exception e) {
throw new FlowException(
"Last ViewContext can't be destroyed!", e);
}
}
}
currentViewWrapper.set(newView);
flowContextWrapper.get().setCurrentViewContext(getCurrentView().getViewContext());
containerWrapper.get().setViewContext(getCurrentView().getViewContext());
return newView.getViewContext();
}
public void navigateBack() throws VetoException, FlowException {
navigateToHistoryIndex(0);
}
public ObservableList> getControllerHistory() {
return FXCollections.unmodifiableObservableList(controllerHistory);
}
public void navigateToHistoryIndex(int index) throws VetoException, FlowException {
handle(new FlowLink(controllerHistory.remove(index).getControllerClass()), "backAction-" + UUID.randomUUID().toString());
}
public void attachAction(Node node, Runnable action) {
if (node instanceof ButtonBase) {
((ButtonBase) node).setOnAction((e) -> action.run());
} else {
node.setOnMouseClicked((ev) -> {
if (ev.getClickCount() > 1) {
action.run();
}
});
}
}
public void attachAction(MenuItem menuItem, Runnable action) {
menuItem.setOnAction((e) -> action.run());
}
public void attachEventHandler(Node node, String actionId) {
if (node instanceof ButtonBase) {
((ButtonBase) node).setOnAction((e) -> handleActionWithExceptionHandler(actionId));
} else {
node.setOnMouseClicked((e) -> {
if (e.getClickCount() > 1) {
handleActionWithExceptionHandler(actionId);
}
});
}
}
public void attachBackEventHandler(MenuItem menuItem) {
menuItem.setOnAction((e) -> handleBackActionWithExceptionHandler());
}
public void attachBackEventHandler(Node node) {
if (node instanceof ButtonBase) {
((ButtonBase) node).setOnAction((e) -> handleBackActionWithExceptionHandler());
} else {
node.setOnMouseClicked((e) -> {
if (e.getClickCount() > 1) {
handleBackActionWithExceptionHandler();
}
});
}
}
public void attachEventHandler(MenuItem menuItem, String actionId) {
menuItem.setOnAction((e) -> handleActionWithExceptionHandler(actionId));
}
private void handleActionWithExceptionHandler(String id) {
try {
handle(id);
} catch (VetoException | FlowException e) {
getExceptionHandler().setException(e);
}
}
private void handleBackActionWithExceptionHandler() {
try {
navigateBack();
} catch (VetoException | FlowException e) {
getExceptionHandler().setException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy