/*******************************************************************************
* Copyright (c) 2012 - 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Lars Vogel (Lars.Vogel@gmail.com) - Bug 420835
******************************************************************************/
package org.eclipse.e4.ui.workbench.addons.dndaddon;
import java.util.List;
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.SideValue;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
import org.eclipse.e4.ui.workbench.renderers.swt.TrimBarLayout;
import org.eclipse.e4.ui.workbench.renderers.swt.TrimmedPartLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
*
*/
public class TrimDropAgent extends DropAgent {
private SideValue side;
private MTrimBar trimBar;
/**
* @param manager
*/
public TrimDropAgent(DnDManager manager) {
super(manager);
}
@Override
public boolean canDrop(MUIElement dragElement, DnDInfo info) {
// We only except elements that can go in the trim
if (!(dragElement instanceof MTrimElement)) {
return false;
}
// are we over a 'side' ?
side = getDropSide(info);
return side != null;
}
private SideValue getDropSide(DnDInfo info) {
Shell ds = dndManager.getDragShell();
if (ds.getLayout() instanceof TrimmedPartLayout) {
TrimmedPartLayout tpl = (TrimmedPartLayout) ds.getLayout();
if (tpl.getTrimRect(SWT.TOP).contains(info.cursorPos)) {
return SideValue.TOP;
}
if (tpl.getTrimRect(SWT.BOTTOM).contains(info.cursorPos)) {
return SideValue.BOTTOM;
}
if (tpl.getTrimRect(SWT.LEFT).contains(info.cursorPos)) {
return SideValue.LEFT;
}
if (tpl.getTrimRect(SWT.RIGHT).contains(info.cursorPos)) {
return SideValue.RIGHT;
}
}
return null;
}
private MUIElement getInsertionElement(MUIElement dragElement, DnDInfo info) {
Composite trimComp = (Composite) trimBar.getWidget();
// If we're over the trim bar itself drop at the end
// May need to take margins into account
if (info.curCtrl == trimComp) {
return null;
}
TrimBarLayout tbl = (TrimBarLayout) trimComp.getLayout();
Point trimPos = trimComp.getDisplay().map(null, trimComp, info.cursorPos);
Control trimCtrl = tbl.ctrlFromPoint(trimComp, trimPos);
if (trimCtrl == null) {
return null;
}
if (trimCtrl == dragElement.getWidget()) {
return dragElement;
}
// Are we closer to the 'end' of the trim control ?
// If so insert before the next control (if any)
MUIElement trimElement = (MUIElement) trimCtrl.getData(AbstractPartRenderer.OWNING_ME);
if (isAfter(trimCtrl, info)) {
MElementContainer<MUIElement> trimParent = trimElement.getParent();
int trimIndex = trimParent.getChildren().indexOf(trimElement);
if (trimIndex == trimParent.getChildren().size() - 1) {
return null;
}
return trimParent.getChildren().get(trimIndex + 1);
}
return trimElement;
}
private boolean isAfter(Control trimCtrl, DnDInfo info) {
Rectangle bounds = trimCtrl.getBounds();
bounds = trimCtrl.getDisplay().map(trimCtrl.getParent(), null, bounds);
Point center = new Point(bounds.x + (bounds.width / 2), bounds.y + (bounds.height / 2));
boolean horizontal = trimBar.getSide() == SideValue.TOP
|| trimBar.getSide() == SideValue.BOTTOM;
boolean after = horizontal ? info.cursorPos.x > center.x : info.cursorPos.y > center.y;
return after;
}
@Override
public void dragEnter(MUIElement dragElement, DnDInfo info) {
super.dragEnter(dragElement, info);
MTrimmedWindow window = (MTrimmedWindow) dndManager.getDragWindow();
trimBar = dndManager.getModelService().getTrim(window, side);
trimBar.setToBeRendered(true);
dragElement.setVisible(true);
track(dragElement, info);
dndManager.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND));
}
@Override
public void dragLeave(MUIElement dragElement, DnDInfo info) {
trimBar = null;
side = null;
dndManager.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_NO));
super.dragLeave(dragElement, info);
}
@Override
public boolean track(MUIElement dragElement, DnDInfo info) {
SideValue curSide = getDropSide(info);
if (side != curSide) {
return false;
}
MUIElement insertBefore = getInsertionElement(dragElement, info);
// Check for no-ops
MUIElement curParent = dragElement.getParent();
List<MTrimElement> trimKids = trimBar.getChildren();
boolean sameParent = curParent == trimBar;
boolean alreadyThere = false;
if (sameParent) {
if (insertBefore == null) {
alreadyThere = trimKids.get(trimKids.size() - 1) == dragElement;
} else {
alreadyThere = insertBefore == dragElement; // Reflexive
if (!alreadyThere) {
alreadyThere = trimKids.indexOf(dragElement) == (trimKids.indexOf(insertBefore) - 1);
}
}
}
if (!sameParent || !alreadyThere) {
dock(dragElement, insertBefore);
}
return true;
}
private void dock(MUIElement dragElement, MUIElement insertBefore) {
dragElement.setToBeRendered(false);
dragElement.getParent().getChildren().remove(dragElement);
dragElement.setVisible(true);
if (insertBefore == null) {
trimBar.getChildren().add((MTrimElement) dragElement);
} else {
int dropIndex = trimBar.getChildren().indexOf(insertBefore);
trimBar.getChildren().add(dropIndex, (MTrimElement) dragElement);
}
dragElement.setToBeRendered(true);
Control trimCtrl = (Control) dragElement.getWidget();
trimCtrl.setBackground(trimCtrl.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
}
@Override
public boolean drop(MUIElement dragElement, DnDInfo info) {
Control trimCtrl = (Control) dragElement.getWidget();
trimCtrl.setBackground(null);
return true;
}
}