/*
* 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.kie.workbench.common.stunner.core.client.canvas.controls.actions;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import com.google.gwt.user.client.ui.IsWidget;
import org.jboss.errai.common.client.ui.ElementWrapperWidget;
import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvas;
import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler;
import org.kie.workbench.common.stunner.core.client.canvas.Canvas;
import org.kie.workbench.common.stunner.core.client.canvas.controls.AbstractCanvasHandlerRegistrationControl;
import org.kie.workbench.common.stunner.core.client.canvas.event.CanvasFocusedEvent;
import org.kie.workbench.common.stunner.core.client.canvas.event.keyboard.KeyDownEvent;
import org.kie.workbench.common.stunner.core.client.canvas.event.keyboard.KeyboardEvent;
import org.kie.workbench.common.stunner.core.client.canvas.event.selection.CanvasElementSelectedEvent;
import org.kie.workbench.common.stunner.core.client.components.actions.NameEditBox;
import org.kie.workbench.common.stunner.core.client.components.views.FloatingView;
import org.kie.workbench.common.stunner.core.client.shape.Shape;
import org.kie.workbench.common.stunner.core.client.shape.view.HasEventHandlers;
import org.kie.workbench.common.stunner.core.client.shape.view.HasTitle;
import org.kie.workbench.common.stunner.core.client.shape.view.ShapeView;
import org.kie.workbench.common.stunner.core.client.shape.view.event.TextDoubleClickEvent;
import org.kie.workbench.common.stunner.core.client.shape.view.event.TextDoubleClickHandler;
import org.kie.workbench.common.stunner.core.client.shape.view.event.TextEnterEvent;
import org.kie.workbench.common.stunner.core.client.shape.view.event.TextEnterHandler;
import org.kie.workbench.common.stunner.core.client.shape.view.event.TextExitEvent;
import org.kie.workbench.common.stunner.core.client.shape.view.event.TextExitHandler;
import org.kie.workbench.common.stunner.core.client.shape.view.event.ViewEventType;
import org.kie.workbench.common.stunner.core.graph.Element;
import org.kie.workbench.common.stunner.core.graph.content.view.View;
import org.kie.workbench.common.stunner.core.graph.util.GraphUtils;
import org.uberfire.mvp.Command;
import static org.uberfire.commons.validation.PortablePreconditions.checkNotNull;
@Dependent
public class CanvasNameEditionControlImpl
extends AbstractCanvasHandlerRegistrationControl<AbstractCanvasHandler>
implements CanvasNameEditionControl<AbstractCanvasHandler, Element> {
private static final int FLOATING_VIEW_TIMEOUT = 3000;
private static final double SHAPE_EDIT_ALPH = 0.2d;
private final FloatingView<IsWidget> floatingView;
private final NameEditBox<AbstractCanvasHandler, Element> nameEditBox;
private final Event<CanvasElementSelectedEvent> elementSelectedEvent;
private String uuid;
private final Command floatingHideCallback = CanvasNameEditionControlImpl.this::hide;
@Inject
public CanvasNameEditionControlImpl(final FloatingView<IsWidget> floatingView,
final NameEditBox<AbstractCanvasHandler, Element> nameEditBox,
final Event<CanvasElementSelectedEvent> elementSelectedEvent) {
this.floatingView = floatingView;
this.nameEditBox = nameEditBox;
this.elementSelectedEvent = elementSelectedEvent;
this.uuid = null;
}
@Override
public void enable(final AbstractCanvasHandler canvasHandler) {
super.enable(canvasHandler);
nameEditBox.initialize(canvasHandler,
() -> {
final String idToSelect = CanvasNameEditionControlImpl.this.uuid;
CanvasNameEditionControlImpl.this.hide();
elementSelectedEvent.fire(new CanvasElementSelectedEvent(canvasHandler,
idToSelect));
});
// TODO: move folatingView to support IsElement instead of IsWidget
floatingView
.hide()
.setHideCallback(floatingHideCallback)
.setTimeOut(FLOATING_VIEW_TIMEOUT)
.add(ElementWrapperWidget.getWidget(nameEditBox.getElement()));
}
@Override
public void register(final Element element) {
if (checkNotRegistered(element)) {
final Shape<?> shape = getShape(element.getUUID());
if (null != shape) {
final ShapeView shapeView = shape.getShapeView();
if (shapeView instanceof HasEventHandlers) {
final HasEventHandlers hasEventHandlers = (HasEventHandlers) shapeView;
if (hasEventHandlers.supports(ViewEventType.TEXT_DBL_CLICK)) {
final TextDoubleClickHandler clickHandler = new TextDoubleClickHandler() {
@Override
public void handle(final TextDoubleClickEvent event) {
CanvasNameEditionControlImpl.this.show(element,
event.getClientX(),
event.getClientY());
}
};
hasEventHandlers.addHandler(ViewEventType.TEXT_DBL_CLICK,
clickHandler);
registerHandler(shape.getUUID(),
clickHandler);
// Change mouse cursor, if shape supports it.
if (hasEventHandlers.supports(ViewEventType.TEXT_ENTER) &&
hasEventHandlers.supports(ViewEventType.TEXT_EXIT)) {
final TextEnterHandler enterHandler = new TextEnterHandler() {
@Override
public void handle(TextEnterEvent event) {
canvasHandler.getAbstractCanvas().getView().setCursor(AbstractCanvas.Cursors.TEXT);
}
};
hasEventHandlers.addHandler(ViewEventType.TEXT_ENTER,
enterHandler);
registerHandler(shape.getUUID(),
enterHandler);
final TextExitHandler exitHandler = new TextExitHandler() {
@Override
public void handle(TextExitEvent event) {
canvasHandler.getAbstractCanvas().getView().setCursor(AbstractCanvas.Cursors.AUTO);
}
};
hasEventHandlers.addHandler(ViewEventType.TEXT_EXIT,
exitHandler);
registerHandler(shape.getUUID(),
exitHandler);
}
}
}
}
}
}
@Override
public CanvasNameEditionControl<AbstractCanvasHandler, Element> show(final Element item,
final double x,
final double y) {
this.uuid = item.getUUID();
enableShapeEdit();
nameEditBox.show(item);
double[] size;
try {
size = GraphUtils.getNodeSize((View) item.getContent());
} catch (final ClassCastException e) {
size = null;
}
final double rx = null != size ? size[0] / 2 : 0d;
floatingView
.setX(x - rx)
.setY(y)
.show();
return this;
}
@Override
public CanvasNameEditionControl<AbstractCanvasHandler, Element> hide() {
if (isVisible()) {
disableShapeEdit();
this.uuid = null;
nameEditBox.hide();
floatingView.hide();
}
return this;
}
@Override
public void setCommandManagerProvider(final CommandManagerProvider<AbstractCanvasHandler> provider) {
nameEditBox.setCommandManagerProvider(provider);
}
@Override
protected void doDisable() {
super.doDisable();
disableShapeEdit();
this.uuid = null;
nameEditBox.hide();
floatingView.destroy();
}
private boolean enableShapeEdit() {
return setShapeEditMode(true);
}
private boolean disableShapeEdit() {
return setShapeEditMode(false);
}
private boolean setShapeEditMode(final boolean editMode) {
final Shape<?> shape = getShape(this.uuid);
if (null != shape) {
final HasTitle hasTitle = (HasTitle) shape.getShapeView();
final double alpha = editMode ? SHAPE_EDIT_ALPH : 1d;
shape.getShapeView().setFillAlpha(alpha);
hasTitle.setTitleAlpha(alpha);
getCanvas().draw();
return true;
}
return false;
}
private Shape<?> getShape(final String uuid) {
return null != uuid ? getCanvas().getShape(uuid) : null;
}
private boolean isVisible() {
return null != this.uuid;
}
private Canvas getCanvas() {
return canvasHandler.getCanvas();
}
void onKeyDownEvent(final @Observes KeyDownEvent keyDownEvent) {
checkNotNull("keyDownEvent",
keyDownEvent);
final KeyboardEvent.Key key = keyDownEvent.getKey();
if (null != key && KeyboardEvent.Key.ESC.equals(key)) {
hide();
}
}
void onCanvasFocusedEvent(final @Observes CanvasFocusedEvent canvasFocusedEvent) {
checkNotNull("canvasFocusedEvent",
canvasFocusedEvent);
hide();
}
}