org.jacpfx.rcp.workbench.AFXWorkbench Maven / Gradle / Ivy
The newest version!
/*
* **********************************************************************
*
* Copyright (C) 2010 - 2015
*
* [AFXWorkbench.java]
* JACPFX Project (https://github.com/JacpFX/JacpFX/)
* All rights reserved.
*
* 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.jacpfx.rcp.workbench;
import javafx.application.Platform;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.stage.Stage;
import org.jacpfx.api.annotations.workbench.Workbench;
import org.jacpfx.api.component.Injectable;
import org.jacpfx.api.component.Perspective;
import org.jacpfx.api.component.RootComponent;
import org.jacpfx.api.componentLayout.WorkbenchLayout;
import org.jacpfx.api.context.JacpContext;
import org.jacpfx.api.coordinator.Coordinator;
import org.jacpfx.api.delegator.ComponentDelegator;
import org.jacpfx.api.delegator.MessageDelegator;
import org.jacpfx.api.handler.ComponentHandler;
import org.jacpfx.api.launcher.Launcher;
import org.jacpfx.api.message.Message;
import org.jacpfx.api.workbench.Base;
import org.jacpfx.rcp.componentLayout.FXComponentLayout;
import org.jacpfx.rcp.componentLayout.FXWorkbenchLayout;
import org.jacpfx.rcp.components.managedFragment.ManagedFragment;
import org.jacpfx.rcp.components.workbench.WorkbenchDecorator;
import org.jacpfx.rcp.context.Context;
import org.jacpfx.rcp.context.JacpContextImpl;
import org.jacpfx.rcp.coordinator.MessageCoordinator;
import org.jacpfx.rcp.delegator.ComponentDelegatorImpl;
import org.jacpfx.rcp.delegator.MessageDelegatorImpl;
import org.jacpfx.rcp.handler.PerspectiveHandlerImpl;
import org.jacpfx.rcp.message.MessageImpl;
import org.jacpfx.rcp.perspective.AFXPerspective;
import org.jacpfx.rcp.registry.ComponentRegistry;
import org.jacpfx.rcp.registry.PerspectiveRegistry;
import org.jacpfx.rcp.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* represents the basic JavaFX workbench instance; handles perspective and
* component;
*
* @author Andy Moncsek, Patrick Symmangk
*/
public abstract class AFXWorkbench
implements
Base, Event, Object>,
RootComponent, Event, Object>, Message> {
private final ComponentDelegator, Event, Object> componentDelegator = new ComponentDelegatorImpl();
private final MessageDelegator, Event, Object> messageDelegator = new MessageDelegatorImpl();
private final WorkbenchLayout workbenchLayout = new FXWorkbenchLayout();
private final Logger logger = Logger.getLogger(getClass().getName());
private List, Event, Object>> perspectives;
private ComponentHandler, Event, Object>, Message> componentHandler;
private Coordinator, Event, Object> messageCoordinator;
private WorkbenchDecorator workbenchDecorator;
private Launcher> launcher;
private Stage stage;
private Context context;
private FXWorkbench handle;
/**
* JavaFX specific start sequence
*
* @param stage, The JavaFX stage
*/
private void start(final Stage stage) {
this.stage = stage;
DimensionUtil.init(stage);
registerTeardownActions();
log("1: init workbench");
initWorkbenchHandle(stage);
log("3: handle initialisation sequence");
perspectives = WorkbenchUtil.getInstance(launcher).createPerspectiveInstances(getWorkbenchAnnotation());
if (perspectives == null) return;
initSubsystem();
handleInitialisationSequence();
}
private void initWorkbenchHandle(final Stage stage) {
// init user defined workspace
handle.handleInitialLayout(new MessageImpl(context.getId(), "init"),
getWorkbenchLayout(), stage);
initWorkbenchDecorator(stage);
handle.postHandle(new FXComponentLayout(getWorkbenchLayout()
.getMenu(), workbenchDecorator.getGlassPane(), null, getContext().getId()));
}
private void initWorkbenchDecorator(Stage stage) {
workbenchDecorator.setWorkbenchLayout(getWorkbenchLayout());
workbenchDecorator.initBasicLayout(stage);
SceneUtil.setScene(stage.getScene());
}
private void registerTeardownActions() {
TearDownHandler.registerBase(this);
stage.setOnCloseRequest(arg0 -> {
ShutdownThreadsHandler.shutdowAll();
TearDownHandler.handleGlobalTearDown();
ComponentRegistry.clearOnShutdown();
PerspectiveRegistry.clearOnShutdown();
Platform.exit();
});
}
private void initSubsystem() {
componentHandler = new PerspectiveHandlerImpl(launcher,
workbenchLayout, workbenchDecorator.getRoot());
messageCoordinator.setPerspectiveHandler(componentHandler);
componentDelegator.setPerspectiveHandler(componentHandler);
messageDelegator.setPerspectiveHandler(componentHandler);
}
@Override
/**
* {@inheritDoc}
*/
public void init(final Launcher> launcher, Object root) {
this.launcher = launcher;
ManagedFragment.initManagedFragment(launcher);
final Workbench annotation = getWorkbenchAnnotation();
messageCoordinator = MessageCoordinator.build().
parentId(annotation.id()).
launcher(launcher).
delegateQueue(messageDelegator.getMessageDelegateQueue()).
handler(null);
context = new JacpContextImpl(annotation.id(), annotation.name(), messageCoordinator.getMessageQueue());
FXUtil.performResourceInjection(handle, context);
start(Stage.class.cast(root));
GlobalMediator.getInstance().handleWorkbenchToolBarButtons(annotation.id(), true);
logger.info("INIT");
}
private Workbench getWorkbenchAnnotation() {
return handle.getClass().getAnnotation(Workbench.class);
}
@Override
/**
* {@inheritDoc}
*/
public final void initComponents(final Message action) {
final AtomicInteger counter = new AtomicInteger(0);
final List, Event, Object>> activePerspectives = perspectives.
stream().
peek(this::registerComponent).
filter(p -> p.getContext().isActive()).
collect(Collectors.toList());
final AtomicInteger of = new AtomicInteger(activePerspectives.size());
activePerspectives.
stream().
peek(p ->
p.updatePositions(counter.incrementAndGet(), of.get())).
peek(this::initActivePerspective).
filter(Perspective::isLast).
findFirst().
ifPresent(p -> {
activePerspectives.remove(p);
GlobalMediator.getInstance().handleToolBarButtons(p, true);
// hide local buttons from other perspectives
activePerspectives.
forEach(persp -> GlobalMediator.getInstance().handleToolBarButtons(persp, false));
});
}
private void initActivePerspective(Perspective, Event, Object> perspective) {
log("3.4.1: register component: " + perspective.getContext().getName());
final CountDownLatch waitForInit = new CountDownLatch(1);
log("3.4.2: init perspective");
executeOnFXThread(() -> {
componentHandler.initComponent(new MessageImpl(perspective.getContext().getId(), perspective
.getContext().getId(), "init", null), perspective);
waitForInit.countDown();
});
waitForPerspectiveInitialisation(waitForInit);
}
private static void waitForPerspectiveInitialisation(CountDownLatch waitForInit) {
final Thread t = Thread.currentThread();
try {
// wait for possible async execution
waitForInit.await();
} catch (InterruptedException e) {
t.getUncaughtExceptionHandler().uncaughtException(t, e);
}
}
private static void executeOnFXThread(Runnable r) {
if (Platform.isFxApplicationThread()) {
r.run();
} else {
Platform.runLater(r);
}
}
/**
* handles sequence for workbench size, menu bar, tool bar and perspective
* initialisation
*/
private void handleInitialisationSequence() {
stage.show();
// start perspective Observer worker thread
// TODO create status daemon which observes
// thread component on
// failure and restarts if needed!!
((Thread) messageCoordinator)
.start();
((Thread) componentDelegator)
.start();
((Thread) messageDelegator)
.start();
// handle perspective
log("3.3: workbench init perspective");
initComponents(null);
}
@Override
/**
* {@inheritDoc}
*/
public final void registerComponent(
final Perspective, Event, Object> perspective) {
final String perspectiveId = PerspectiveUtil.getPerspectiveIdFromAnnotation(perspective);
final MessageCoordinator messageCoordinatorLocal = MessageCoordinator.build().
parentId(perspectiveId).
launcher(launcher).
delegateQueue(messageDelegator.getMessageDelegateQueue()).
handler(componentHandler);
// use compleatableFuture
perspective.init(componentDelegator.getComponentDelegateQueue(),
messageDelegator.getMessageDelegateQueue(),
messageCoordinatorLocal, launcher);
messageCoordinatorLocal.start();
WorkbenchUtil.handleMetaAnnotation(perspective, getWorkbenchAnnotation().id());
addComponent(perspective);
}
@Override
public final void addComponent(
final Perspective, Event, Object> perspective) {
PerspectiveRegistry.registerPerspective(perspective);
}
@Override
/**
* {@inheritDoc}
*/
// TODO remove this!!
public final void unregisterComponent(
final Perspective, Event, Object> perspective) {
FXUtil.setPrivateMemberValue(AFXPerspective.class, perspective,
FXUtil.APERSPECTIVE_MQUEUE, null);
PerspectiveRegistry.removePerspective(perspective);
}
@Override
public final void removeAllCompnents() {
perspectives.forEach(this::unregisterComponent);
perspectives.clear();
}
/**
* {@inheritDoc}
*/
private FXWorkbenchLayout getWorkbenchLayout() {
return (FXWorkbenchLayout) workbenchLayout;
}
@Override
public ComponentHandler, Event, Object>, Message> getComponentHandler() {
return componentHandler;
}
@Override
/**
* {@inheritDoc}
*/
public final List, Event, Object>> getPerspectives() {
return perspectives;
}
private void log(final String message) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(">> " + message);
}
}
@Override
public JacpContext getContext() {
return context;
}
private FXWorkbench getWorkbenchHandle() {
return handle;
}
@SuppressWarnings("unchecked")
@Override
public FXWorkbench getComponentHandle() {
return handle;
}
@Override
public void setComponentHandle(X handle) {
this.handle = (FXWorkbench) handle;
}
protected WorkbenchDecorator getWorkbenchDecorator() {
return this.workbenchDecorator;
}
protected void setWorkbenchDecorator(WorkbenchDecorator workbenchDecorator) {
this.workbenchDecorator = workbenchDecorator;
}
}