package com.project.website.canvas.client.worksheet; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HumanInputEvent; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.Widget; import com.project.shared.client.events.SimpleEvent; import com.project.shared.client.events.SimpleEvent.Handler; import com.project.shared.client.handlers.RegistrationsManager; import com.project.shared.client.utils.ElementUtils; import com.project.shared.client.utils.EventUtils; import com.project.shared.client.utils.widgets.WidgetUtils; import com.project.shared.data.Point2D; import com.project.website.canvas.client.worksheet.exceptions.InvalidDragPanelRelationshipException; import com.project.website.canvas.client.worksheet.interfaces.ElementDragManager; import com.project.website.canvas.client.worksheet.interfaces.MouseMoveOperationHandler; public class ElementDragManagerImpl implements ElementDragManager { public final static int DEFAULT_DRAG_START_SENSITIVITY = 5; private Widget _container; private Widget _dragPanel; private String _targetDragStyleName = ""; private SimpleEvent<Void> _stopOperationEvent; private int _dragStartSensitivity = DEFAULT_DRAG_START_SENSITIVITY; public ElementDragManagerImpl(Widget container, Widget dragPanel, SimpleEvent<Void> stopOperationEvent) { this(container, dragPanel, 5, stopOperationEvent); } public ElementDragManagerImpl(Widget container, Widget dragPanel, int dragStartSensitivity, SimpleEvent<Void> stopOperationEvent) { this(container, dragPanel, "", dragStartSensitivity, stopOperationEvent); } public ElementDragManagerImpl(Widget container, Widget dragPanel, String targetDragStyleName, SimpleEvent<Void> stopOperationEvent) { this(container, dragPanel, targetDragStyleName, 5, stopOperationEvent); } public ElementDragManagerImpl(Widget container, Widget dragPanel, String targetDragStyleName, int dragStartSensitivity, SimpleEvent<Void> stopOperationEvent) { this.validateDragPanel(container, dragPanel); this._container = container; this._dragPanel = dragPanel; this._targetDragStyleName = targetDragStyleName; this._stopOperationEvent = stopOperationEvent; this._dragStartSensitivity = dragStartSensitivity; } protected void validateDragPanel(Widget container, Widget dragPanel) { Element containerElement = container.getElement(); Element dragPanelElement = dragPanel.getElement(); if (containerElement == dragPanelElement) { throw new InvalidDragPanelRelationshipException(); } if (false == containerElement.isOrHasChild(dragPanelElement)) { throw new InvalidDragPanelRelationshipException(); } } @Override public SimpleEvent.Handler<Void> startMouseMoveOperation( final Element targetElement, final Point2D referenceOffset, MouseMoveOperationHandler handler, int stopConditions) { return this.startMouseMoveOperation(targetElement, targetElement, referenceOffset, handler, stopConditions); } @Override public SimpleEvent.Handler<Void> startMouseMoveOperation( final Element targetElement, final Element referenceElem, final Point2D referenceOffset, final MouseMoveOperationHandler handler, int stopConditions) { final RegistrationsManager regs = new RegistrationsManager(); if (false == setStopConditionHandlers(targetElement, referenceElem, referenceOffset, handler, stopConditions, regs)) { throw new RuntimeException("Must specify at least one stop condition. The bitfield was: " + stopConditions); } ElementUtils.setTextSelectionEnabled(_container.getElement(), false); final MouseDragHandler dragHandler = new MouseDragHandler( EventUtils.getCurrentMousePos(), this._dragStartSensitivity); regs.add(dragHandler.addDragStartedHandler(new SimpleEvent.Handler<HumanInputEvent<?>>() { @Override public void onFire(HumanInputEvent<?> arg) { ElementUtils.addClassName(targetElement, _targetDragStyleName); _dragPanel.setVisible(true); handler.onStart(); arg.preventDefault(); } })); regs.add(dragHandler.addDragHandler(new SimpleEvent.Handler<HumanInputEvent<?>>() { @Override public void onFire(HumanInputEvent<?> arg) { handleMouseMove(referenceElem, referenceOffset, handler); arg.preventDefault(); } })); regs.add(WidgetUtils.addMovementMoveHandler(_container, dragHandler)); if (null != _stopOperationEvent) { regs.add(_stopOperationEvent.addHandler(new SimpleEvent.Handler<Void>() { @Override public void onFire(Void arg) { stopMouseMoveOperation(targetElement, regs); handler.onCancel(); } })); } return new Handler<Void>() { @Override public void onFire(Void arg) { stopMouseMoveOperation(targetElement, regs); } }; } private void operationEnded(final Element targetElement, final Element referenceElem, Point2D referenceOffset, MouseMoveOperationHandler handler, RegistrationsManager regs) { // Warning: MUST calculate the mouse pos BEFORE calling stopMouseMoveOperation // because stopMouseMoveOperation will cause changes to the DOM (such as hiding the referenceElem) // which will lead to wrong calculations. Point2D pos = calcMousePosition(referenceElem, referenceOffset); stopMouseMoveOperation(targetElement, regs); handler.onStop(pos); } private boolean setStopConditionHandlers(final Element targetElement, final Element referenceElem, final Point2D referenceOffset, final MouseMoveOperationHandler handler, int stopConditions, final RegistrationsManager regs) { boolean stopConditionFound = false; if (0 != (stopConditions & StopCondition.STOP_CONDITION_MOVEMENT_STOP)) { stopConditionFound = true; regs.add(WidgetUtils.addMovementStopHandler(_container, new Handler<HumanInputEvent<?>>() { @Override public void onFire(HumanInputEvent<?> arg) { operationEnded(targetElement, referenceElem, referenceOffset, handler, regs); }})); } if (0 != (stopConditions & StopCondition.STOP_CONDITION_MOUSE_CLICK)) { stopConditionFound = true; regs.add(_container.addDomHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { operationEnded(targetElement, referenceElem, referenceOffset, handler, regs); } }, ClickEvent.getType())); } return stopConditionFound; } private void stopMouseMoveOperation(Element targetElement, RegistrationsManager regs) { ElementUtils.removeClassName(targetElement, this._targetDragStyleName); // TODO: restore the previous state of text selection enabled from before the mouse operation, instead of // forcing it to "true" ElementUtils.setTextSelectionEnabled(_container.getElement(), true); _dragPanel.setVisible(false); regs.clear(); } private void handleMouseMove(Element referenceElem, Point2D referenceOffset, MouseMoveOperationHandler handler) { handler.onMouseMove(calcMousePosition(referenceElem, referenceOffset)); } private Point2D calcMousePosition(Element referenceElem, Point2D referenceOffset) { return ElementUtils.getMousePositionRelativeToElement(referenceElem).minus(referenceOffset); } }