| /******************************************************************************* |
| * Copyright (c) 2012 Rushan R. Gilmullin and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Rushan R. Gilmullin - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.osbp.vaaclipse.presentation.dnd; |
| |
| import javax.inject.Inject; |
| |
| import org.eclipse.e4.core.di.annotations.Optional; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.ui.MUIElement; |
| import org.eclipse.e4.ui.model.application.ui.advanced.MArea; |
| import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; |
| import org.eclipse.e4.ui.model.application.ui.basic.MStackElement; |
| import org.eclipse.e4.ui.model.application.ui.basic.MWindow; |
| import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicFactoryImpl; |
| import org.eclipse.e4.ui.workbench.modeling.EModelService; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.osbp.commons.geom.GeomUtils; |
| import org.eclipse.osbp.commons.geom.Side; |
| import org.eclipse.osbp.commons.geom.Vector; |
| import org.eclipse.osbp.vaaclipse.publicapi.change.ChangeCommand; |
| import org.eclipse.osbp.vaaclipse.widgets.StackWidget; |
| |
| import com.vaadin.event.dd.DragAndDropEvent; |
| import com.vaadin.event.dd.DropHandler; |
| import com.vaadin.event.dd.acceptcriteria.AcceptAll; |
| import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; |
| import com.vaadin.shared.ui.dd.HorizontalDropLocation; |
| import com.vaadin.ui.AbstractComponent; |
| import com.vaadin.ui.TabSheet.Tab; |
| |
| import fi.jasoft.dragdroplayouts.DDTabSheet.TabSheetTargetDetails; |
| import fi.jasoft.dragdroplayouts.events.LayoutBoundTransferable; |
| |
| /** |
| * @author rushan |
| * |
| */ |
| public class VaadinDropHandler implements DropHandler { |
| private MPartStack targetPartStack; |
| private StackWidget targetTabSheet; |
| |
| @Inject |
| EModelService modelService; |
| |
| @Inject |
| MApplication app; |
| |
| @Inject |
| @Optional |
| private EditingDomain editingDomain; |
| |
| @Inject |
| public VaadinDropHandler(MPartStack targetPartStack) { |
| this.targetPartStack = targetPartStack; |
| targetTabSheet = (StackWidget) targetPartStack.getWidget(); |
| } |
| |
| public AcceptCriterion getAcceptCriterion() { |
| // Only allow dropping between tabs |
| // return new Not(HorizontalLocationIs.CENTER); |
| |
| return AcceptAll.get(); |
| } |
| |
| public void drop(final DragAndDropEvent event) { |
| if (!(event.getTransferable() instanceof LayoutBoundTransferable)) |
| return; |
| |
| ChangeCommand command = new ChangeCommand("Drop part", ((EObject) app).eResource()) { |
| @Override |
| protected void doExecute() { |
| doDrop(event); |
| } |
| }; |
| editingDomain.getCommandStack().execute(command); |
| } |
| |
| protected void doDrop(DragAndDropEvent event) { |
| LayoutBoundTransferable transferable = (LayoutBoundTransferable) event |
| .getTransferable(); |
| TabSheetTargetDetails details = (TabSheetTargetDetails) event |
| .getTargetDetails(); |
| |
| if (transferable.getSourceComponent() instanceof StackWidget) { |
| StackWidget sourceTabSheet = (StackWidget) transferable |
| .getSourceComponent(); |
| |
| MPartStack targetFolder = targetPartStack; |
| MPartStack sourceFolder = (MPartStack) sourceTabSheet.getData(); |
| |
| // this component is dragged by user |
| AbstractComponent draggingComponent = (AbstractComponent) transferable |
| .getComponent(); |
| // This is model element that match to draggingComponent |
| MStackElement draggingElement = (MStackElement) draggingComponent |
| .getData(); |
| |
| // draggingElement must be in sourceFolder |
| if (!sourceFolder.getChildren().contains(draggingElement)) |
| return; |
| |
| String dropType = (String) details.getData("dropType"); |
| |
| if (dropType.equals("DropToTabsheetBar")) { |
| int idx = details.getOverIndex(); |
| HorizontalDropLocation location = details.getDropLocation(); |
| |
| if (draggingComponent == details.getOverComponent()) { |
| // Dropped on itself |
| return; |
| } |
| |
| if (sourceTabSheet == targetTabSheet) {// reordering tabs |
| |
| if (sourceFolder != targetFolder) |
| return; |
| int modelOldPos = sourceFolder.getChildren().indexOf( |
| draggingElement); |
| |
| Tab tabInNewPos = targetTabSheet.getTab(idx); |
| |
| if (tabInNewPos == null) |
| return; |
| |
| MUIElement elementInInsertPos = (MUIElement) ((AbstractComponent) tabInNewPos |
| .getComponent()).getData(); |
| int modelNewPos = targetPartStack.getChildren().indexOf( |
| elementInInsertPos); |
| |
| targetPartStack.getChildren().remove(draggingElement); |
| |
| if (location == HorizontalDropLocation.RIGHT) { |
| |
| if (modelOldPos > modelNewPos) |
| targetPartStack.getChildren().add(modelNewPos + 1, |
| draggingElement); |
| else |
| targetPartStack.getChildren().add(modelNewPos, |
| draggingElement); |
| } else {// LEFT OR CENTER - processed as LEFT |
| if (modelOldPos > modelNewPos) |
| targetPartStack.getChildren().add(modelNewPos, |
| draggingElement); |
| else |
| targetPartStack.getChildren().add(modelNewPos - 1, |
| draggingElement); |
| |
| } |
| } else {// Adding new tab |
| sourceFolder.getChildren().remove(draggingElement); |
| |
| if (idx == -1) |
| targetFolder.getChildren().add(draggingElement); |
| else { |
| Tab tabInNewPos = targetTabSheet.getTab(idx); |
| MUIElement elementInNewPos = (MUIElement) ((AbstractComponent) tabInNewPos |
| .getComponent()).getData(); |
| int modelNewPos = targetPartStack.getChildren() |
| .indexOf(elementInNewPos); |
| |
| int newPos = -1; |
| if (location == HorizontalDropLocation.RIGHT) { |
| targetFolder.getChildren().add(modelNewPos + 1, |
| draggingElement); |
| } else {// LEFT or CENTER - processed both as LEFT |
| targetFolder.getChildren().add(modelNewPos, |
| draggingElement); |
| } |
| } |
| } |
| targetFolder.setSelectedElement(draggingElement); |
| } else if (dropType.equals("DropToTabsheetBody")) { |
| // target widget coordinates: |
| int x0 = (Integer) details.getData("targetWidgetAbsoluteLeft"); |
| int y0 = (Integer) details.getData("targetWidgetAbsoluteTop"); |
| int dx = (Integer) details.getData("targetWidgetOffsetWidth"); |
| int dy = (Integer) details.getData("targetWidgetOffsetHeight"); |
| |
| int docPrcnt = 30; |
| double docX = dx * docPrcnt / 100; |
| double docY = dy * docPrcnt / 100; |
| |
| int mouseX = details.getMouseEvent().getClientX(); |
| int mouseY = details.getMouseEvent().getClientY(); |
| |
| Vector mousePos = Vector.valueOf(mouseX, mouseY); |
| |
| Integer side = GeomUtils.findDockSide(x0, y0, dx, dy, docX, |
| docY, mousePos); |
| if (side != null) { |
| targetPartStack.getChildren().remove(draggingElement); |
| |
| if (side == Side.CENTER) {// drop in center is equivalent |
| // tab adding at the end of |
| // target folder |
| targetFolder.getChildren().add(draggingElement); |
| targetFolder.setSelectedElement(draggingElement); |
| } else {// if drop to sides, we must different what kind is |
| // target widget - tabsheet or area |
| boolean onEdge = false; |
| |
| // Find the root of the targetFolder's sash structure |
| // This root - is area, perspective or window |
| MUIElement outerRelTo = targetFolder.getParent(); |
| if (outerRelTo instanceof MPartSashContainer) { |
| while (outerRelTo != null |
| && !(outerRelTo instanceof MArea |
| || outerRelTo instanceof MPerspective || outerRelTo instanceof MWindow)) |
| outerRelTo = outerRelTo.getParent(); |
| } |
| |
| // Outer element can not be null, becouse mpartstack or |
| // his sash structure must be located in one of place: |
| // area, perspective or window |
| if (outerRelTo == null) |
| return; |
| |
| if (outerRelTo.getParent() == null |
| && outerRelTo.getCurSharedRef() != null) { |
| outerRelTo = outerRelTo.getCurSharedRef(); |
| } |
| |
| MPartSashContainerElement relTo = null; |
| |
| if (outerRelTo instanceof MArea || onEdge) |
| relTo = (MPartSashContainerElement) outerRelTo; |
| else |
| relTo = targetFolder; |
| |
| // store original container data for using after model |
| // operations |
| String containerDataBeforeModelOperations = targetFolder |
| .getContainerData(); |
| |
| // wrap it in a stack if it's a part |
| MPartStack toInsert; |
| MStackElement stackElement = (MStackElement) draggingElement; |
| toInsert = BasicFactoryImpl.eINSTANCE.createPartStack(); |
| toInsert.getChildren().add(stackElement); |
| toInsert.setSelectedElement(stackElement); |
| |
| float pct = (float) (onEdge ? 0.15 : 0.3); |
| MUIElement relToParent = relTo.getParent(); |
| modelService |
| .insert(toInsert, relTo, convert(side), pct); |
| |
| // Force the new sash to have the same weight as the |
| // original element |
| if (relTo.getParent() != relToParent && !onEdge) |
| relTo.getParent().setContainerData( |
| containerDataBeforeModelOperations); |
| } |
| } |
| } |
| } |
| } |
| |
| private int convert(Integer side) { |
| if (side == Side.LEFT) |
| return EModelService.LEFT_OF; |
| else if (side == Side.RIGHT) |
| return EModelService.RIGHT_OF; |
| else if (side == Side.BOTTOM) |
| return EModelService.BELOW; |
| else if (side == Side.TOP) |
| return EModelService.ABOVE; |
| else |
| throw new IllegalArgumentException(); |
| } |
| } |