/* * Copyright 2011 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.drools.workbench.screens.guided.dtable.client.widget.table; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.enterprise.context.Dependent; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.inject.Inject; import com.ait.lienzo.client.core.types.Point2D; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; import org.drools.workbench.models.guided.dtable.shared.model.GuidedDecisionTable52; import org.drools.workbench.screens.guided.dtable.client.editor.menu.RadarMenuBuilder; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.DecisionTableColumnSelectedEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.DecisionTablePinnedEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.DecisionTableSelectedEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.RefreshActionsPanelEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.RefreshAttributesPanelEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.RefreshConditionsPanelEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.events.cdi.RefreshMetaDataPanelEvent; import org.drools.workbench.screens.guided.dtable.client.widget.table.popovers.ColumnHeaderPopOver; import org.drools.workbench.screens.guided.dtable.client.widget.table.popovers.ColumnHeaderPopOverHandler; import org.drools.workbench.screens.guided.dtable.client.wizard.column.NewGuidedDecisionTableColumnWizard; import org.drools.workbench.screens.guided.dtable.model.GuidedDecisionTableEditorContent; import org.jboss.errai.ioc.client.api.ManagedInstance; import org.uberfire.backend.vfs.ObservablePath; import org.uberfire.ext.wires.core.grids.client.model.Bounds; import org.uberfire.ext.wires.core.grids.client.widget.grid.GridWidget; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.BaseGridWidgetKeyboardHandler; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationClearCell; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationEditCell; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationMoveDown; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationMoveLeft; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationMoveRight; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationMoveUp; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationSelectBottomRightCell; import org.uberfire.ext.wires.core.grids.client.widget.grid.impl.KeyboardOperationSelectTopLeftCell; import org.uberfire.ext.wires.core.grids.client.widget.layer.GridLayer; import org.uberfire.ext.wires.core.grids.client.widget.layer.pinning.TransformMediator; import org.uberfire.mvp.ParameterizedCommand; import org.uberfire.mvp.PlaceRequest; @Dependent public class GuidedDecisionTableModellerPresenter implements GuidedDecisionTableModellerView.Presenter { private final GuidedDecisionTableModellerView view; private final ManagedInstance<GuidedDecisionTableView.Presenter> dtPresenterProvider; private final Event<RadarMenuBuilder.UpdateRadarEvent> updateRadarEvent; private final Event<DecisionTablePinnedEvent> pinnedEvent; private final ColumnHeaderPopOver columnHeaderPopOver; private final ManagedInstance<NewGuidedDecisionTableColumnWizard> wizardManagedInstance; private GuidedDecisionTableView.Presenter activeDecisionTable = null; private Set<GuidedDecisionTableView.Presenter> availableDecisionTables = new HashSet<GuidedDecisionTableView.Presenter>(); private Set<HandlerRegistration> handlerRegistrations = new HashSet<>(); @Inject public GuidedDecisionTableModellerPresenter(final GuidedDecisionTableModellerView view, final ManagedInstance<GuidedDecisionTableView.Presenter> dtPresenterProvider, final GuidedDecisionTableModellerContextMenuSupport contextMenuSupport, final Event<RadarMenuBuilder.UpdateRadarEvent> updateRadarEvent, final Event<DecisionTablePinnedEvent> pinnedEvent, final ColumnHeaderPopOver columnHeaderPopOver, final ManagedInstance<NewGuidedDecisionTableColumnWizard> wizardManagedInstance) { this.view = view; this.dtPresenterProvider = dtPresenterProvider; this.updateRadarEvent = updateRadarEvent; this.pinnedEvent = pinnedEvent; this.columnHeaderPopOver = columnHeaderPopOver; this.wizardManagedInstance = wizardManagedInstance; this.view.init(this); //Add support for Column PopOver handlerRegistrations.add(view.getGridLayerView().addNodeMouseMoveHandler(new ColumnHeaderPopOverHandler(this, columnHeaderPopOver))); handlerRegistrations.add(view.getGridLayerView().addNodeMouseOutHandler((e) -> columnHeaderPopOver.hide())); //Add support for keyboard operations final GridLayer layer = view.getGridLayerView(); final BaseGridWidgetKeyboardHandler handler = new BaseGridWidgetKeyboardHandler(layer); handler.addOperation(new KeyboardOperationClearCell(layer) { @Override protected void clearCells(final GridWidget gridWidget) { getActiveDecisionTable().onDeleteSelectedCells(); } }, new KeyboardOperationEditCell(layer), new KeyboardOperationMoveLeft(layer), new KeyboardOperationMoveRight(layer), new KeyboardOperationMoveUp(layer), new KeyboardOperationMoveDown(layer), new KeyboardOperationSelectTopLeftCell(layer), new KeyboardOperationSelectBottomRightCell(layer)); handlerRegistrations.add(view.addKeyDownHandler(handler)); //Add support for context menus handlerRegistrations.add(view.addContextMenuHandler(contextMenuSupport.getContextMenuHandler(this))); handlerRegistrations.add(view.addMouseDownHandler(contextMenuSupport.getContextMenuMouseDownHandler())); } @Override public void onClose() { view.clear(); releaseDecisionTables(); releaseHandlerRegistrations(); } @Override public void releaseDecisionTables() { //Release objects created manually with BeanManager availableDecisionTables.stream().forEach(GuidedDecisionTableView.Presenter::onClose); availableDecisionTables.clear(); } @Override public void releaseHandlerRegistrations() { //Release HandlerRegistrations handlerRegistrations.stream().forEach(HandlerRegistration::removeHandler); handlerRegistrations.clear(); } @Override public GuidedDecisionTableView.Presenter addDecisionTable(final ObservablePath path, final PlaceRequest placeRequest, final GuidedDecisionTableEditorContent content, final boolean isReadOnly, final Double x, final Double y) { //Instantiate a Presenter for the Decision Table final GuidedDecisionTableView.Presenter dtPresenter = dtPresenterProvider.get(); //Set content of new Presenter dtPresenter.setContent(path, placeRequest, content, this, isReadOnly); //Add new view to Modeller final double dtViewX = (x == null ? getDecisionTableX(dtPresenter) : x); final double dtViewY = (y == null ? getDecisionTableY(dtPresenter) : y); dtPresenter.getView().setLocation(dtViewX, dtViewY); availableDecisionTables.add(dtPresenter); updateLinks(); view.addDecisionTable(dtPresenter.getView()); return dtPresenter; } private double getDecisionTableX(final GuidedDecisionTableView.Presenter dtPresenter) { final Bounds bounds = getView().getBounds(); final double x = bounds.getX() + (bounds.getWidth() - dtPresenter.getView().getWidth()) / 2; return x; } @SuppressWarnings("unused") private double getDecisionTableY(final GuidedDecisionTableView.Presenter dtPresenter) { final Bounds bounds = getView().getBounds(); double y = bounds.getY() + (bounds.getHeight() * 0.25); for (GuidedDecisionTableView.Presenter p : availableDecisionTables) { y = y + p.getView().getHeight() + 200; } return y; } @Override public GuidedDecisionTableView.Presenter refreshDecisionTable(final GuidedDecisionTableView.Presenter dtPresenter, final ObservablePath path, final PlaceRequest placeRequest, final GuidedDecisionTableEditorContent content, final boolean isReadOnly) { //Remove old view from Modeller final Point2D oldLocation = dtPresenter.getView().getLocation(); view.removeDecisionTable(dtPresenter.getView(), () -> { //Refresh existing Presenter with new content dtPresenter.refreshContent(path, placeRequest, content, isReadOnly); //Add new view to Modeller and ensure selection dtPresenter.getView().setLocation(oldLocation); view.addDecisionTable(dtPresenter.getView()); }); return dtPresenter; } @Override public void removeDecisionTable(final GuidedDecisionTableView.Presenter dtPresenter) { final Command afterRemovalCommand = () -> { view.setEnableColumnCreation(false); view.refreshAttributeWidget(Collections.emptyList()); view.refreshMetaDataWidget(Collections.emptyList()); view.refreshConditionsWidget(Collections.emptyList()); view.refreshActionsWidget(Collections.emptyList()); view.refreshColumnsNote(false); availableDecisionTables.remove(dtPresenter); if (dtPresenter.equals(activeDecisionTable)) { activeDecisionTable = null; } dtPresenter.onClose(); }; view.removeDecisionTable(dtPresenter.getView(), afterRemovalCommand); } @Override public void onLockStatusUpdated(final GuidedDecisionTableView.Presenter dtPresenter) { if (dtPresenter == null) { return; } //Update Definitions Panel if active Decision Table's lock has changed if (dtPresenter.equals(getActiveDecisionTable())) { refreshDefinitionsPanel(dtPresenter); } } @Override public GuidedDecisionTableView.Presenter getActiveDecisionTable() { return activeDecisionTable; } @Override public Set<GuidedDecisionTableView.Presenter> getAvailableDecisionTables() { return Collections.unmodifiableSet(availableDecisionTables); } @Override public boolean isDecisionTableAvailable(final GuidedDecisionTableView.Presenter dtPresenter) { return availableDecisionTables.contains(dtPresenter); } @Override public boolean isActiveDecisionTableEditable() { final GuidedDecisionTableView.Presenter dtPresenter = getActiveDecisionTable(); if (dtPresenter == null) { return false; } return dtPresenter.getAccess().isEditable(); } @Override public GuidedDecisionTableModellerView getView() { return view; } @Override public void setZoom(final int zoom) { view.setZoom(zoom); } @Override public void onInsertColumn() { final GuidedDecisionTableView.Presenter dtPresenter = getActiveDecisionTable(); if (dtPresenter == null) { return; } view.onInsertColumn(); } @Override public void enterPinnedMode(final GridWidget gridWidget, final Command onStartCommand) { columnHeaderPopOver.hide(); view.getGridLayerView().enterPinnedMode(gridWidget, onStartCommand); } @Override public void exitPinnedMode(final Command onCompleteCommand) { columnHeaderPopOver.hide(); view.getGridLayerView().exitPinnedMode(onCompleteCommand); } @Override public void updatePinnedContext(final GridWidget gridWidget) throws IllegalStateException { columnHeaderPopOver.hide(); view.getGridLayerView().updatePinnedContext(gridWidget); } @Override public PinnedContext getPinnedContext() { return view.getGridLayerView().getPinnedContext(); } @Override public boolean isGridPinned() { return view.getGridLayerView().isGridPinned(); } @Override public TransformMediator getDefaultTransformMediator() { return view.getGridLayerView().getDefaultTransformMediator(); } @Override public void onDecisionTableSelected(final @Observes DecisionTableSelectedEvent event) { final GuidedDecisionTableView.Presenter dtPresenter = event.getPresenter(); if (dtPresenter == null) { return; } if (!isDecisionTableAvailable(dtPresenter)) { return; } if (dtPresenter.equals(getActiveDecisionTable())) { return; } doDecisionTableSelected(dtPresenter); } @Override public void openNewGuidedDecisionTableColumnWizard() { final NewGuidedDecisionTableColumnWizard wizard = wizardManagedInstance.get(); wizard.init(activeDecisionTable); wizard.start(); } private void doDecisionTableSelected(final GuidedDecisionTableView.Presenter dtPresenter) { //Store selected decision table activeDecisionTable = dtPresenter; //Bootstrap Decision Table analysis for (GuidedDecisionTableView.Presenter p : getAvailableDecisionTables()) { if (p.equals(dtPresenter)) { p.initialiseAnalysis(); } } //Update view with selected decision table detail final GuidedDecisionTable52 model = dtPresenter.getModel(); dtPresenter.getPackageParentRuleNames(new ParameterizedCommand<Collection<String>>() { @Override public void execute(Collection<String> availableParentRuleNames) { view.refreshRuleInheritance(model.getParentName(), availableParentRuleNames); } }); refreshDefinitionsPanel(dtPresenter); //Delegate highlighting of selected decision table to ISelectionManager view.select(dtPresenter.getView()); //If the Layer is "pinned" flip to the selected Decision Table if (isGridPinned()) { view.getGridLayerView().flipToGridWidget(dtPresenter.getView()); } } void refreshDefinitionsPanel(final GuidedDecisionTableView.Presenter dtPresenter) { final GuidedDecisionTable52 model = dtPresenter.getModel(); view.setEnableColumnCreation(dtPresenter.getAccess().isEditable()); view.refreshAttributeWidget(model.getAttributeCols()); view.refreshMetaDataWidget(model.getMetadataCols()); view.refreshConditionsWidget(model.getConditions()); view.refreshActionsWidget(model.getActionCols()); view.refreshColumnsNote(dtPresenter.hasColumnDefinitions()); } @Override public void onDecisionTableLinkedColumnSelected(final @Observes DecisionTableColumnSelectedEvent event) { if (event.getColumn() == null) { return; } view.selectLinkedColumn(event.getColumn()); } @Override public void onRefreshAttributesPanelEvent(final @Observes RefreshAttributesPanelEvent event) { refreshPanel(event.getPresenter(), event.getColumns(), view::refreshAttributeWidget); } @Override public void onRefreshMetaDataPanelEvent(final @Observes RefreshMetaDataPanelEvent event) { refreshPanel(event.getPresenter(), event.getColumns(), view::refreshMetaDataWidget); } @Override public void onRefreshConditionsPanelEvent(final @Observes RefreshConditionsPanelEvent event) { refreshPanel(event.getPresenter(), event.getColumns(), view::refreshConditionsWidget); } @Override public void onRefreshActionsPanelEvent(final @Observes RefreshActionsPanelEvent event) { refreshPanel(event.getPresenter(), event.getColumns(), view::refreshActionsWidget); } private <C> void refreshPanel(final GuidedDecisionTableView.Presenter dtPresenter, final List<C> columns, final ParameterizedCommand<List<C>> command) { if (dtPresenter == null) { return; } if (!isDecisionTableAvailable(dtPresenter)) { return; } command.execute(columns); } @Override public void updateRadar() { updateRadarEvent.fire(new RadarMenuBuilder.UpdateRadarEvent(this)); } @Override public void onViewPinned(final boolean isPinned) { pinnedEvent.fire(new DecisionTablePinnedEvent(this, isPinned)); } @Override public void updateLinks() { for (GuidedDecisionTableView.Presenter dtPresenter : getAvailableDecisionTables()) { dtPresenter.link(getAvailableDecisionTables()); } getView().getGridLayerView().refreshGridWidgetConnectors(); } }