package com.vaadin.tests.dd;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
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.event.dd.acceptcriteria.Not;
import com.vaadin.event.dd.acceptcriteria.SourceIsTarget;
import com.vaadin.server.Resource;
import com.vaadin.server.StreamResource;
import com.vaadin.server.StreamResource.StreamSource;
import com.vaadin.server.StreamVariable;
import com.vaadin.server.ThemeResource;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.tests.components.TestBase;
import com.vaadin.tests.util.TestUtils;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.DragAndDropWrapper;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Html5File;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.v7.data.Property;
import com.vaadin.v7.data.Property.ValueChangeEvent;
import com.vaadin.v7.data.util.BeanItemContainer;
import com.vaadin.v7.data.util.ContainerHierarchicalWrapper;
import com.vaadin.v7.event.DataBoundTransferable;
import com.vaadin.v7.ui.Table;
import com.vaadin.v7.ui.Tree;
import com.vaadin.v7.ui.Tree.TreeDragMode;
import com.vaadin.v7.ui.Tree.TreeTargetDetails;
public class DDTest6 extends TestBase {
java.util.Random r = new java.util.Random(1);
File[] files = new File[] { new Folder("Docs"), new Folder("Music"),
new Folder("Images"), new File("document.doc"),
new File("song.mp3"), new File("photo.jpg") };
private static Tree tree1;
private HorizontalSplitPanel sp;
private BeanItemContainer<File> fs1;
private static DDTest6 instance;
@Override
protected void setup() {
instance = this; // Note, test only works with single app per server if
// get()
// not converted to thread local
sp = new HorizontalSplitPanel();
sp.setSplitPosition(20);
CssLayout l = new CssLayout();
sp.setFirstComponent(l);
tree1 = new Tree("Volume 1");
tree1.setImmediate(true);
fs1 = new BeanItemContainer<>(File.class);
tree1.setContainerDataSource(fs1);
for (int i = 0; i < files.length; i++) {
fs1.addBean(files[i]);
if (files[i] instanceof Folder) {
tree1.setChildrenAllowed(files[i], true);
} else {
tree1.setChildrenAllowed(files[i], false);
}
if (i >= files.length / 2) {
tree1.setParent(files[i], files[i - files.length / 2]);
}
}
tree1.setItemCaptionPropertyId("name");
tree1.setItemIconPropertyId("icon");
tree1.setDragMode(TreeDragMode.NODE);
DropHandler dropHandler = new DropHandler() {
@Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
@Override
public void drop(DragAndDropEvent dropEvent) {
File file = null;
Folder folder = null;
TreeTargetDetails dropTargetData = (TreeTargetDetails) dropEvent
.getTargetDetails();
folder = (Folder) dropTargetData.getItemIdInto();
if (dropEvent
.getTransferable() instanceof DataBoundTransferable) {
DataBoundTransferable transferable = (DataBoundTransferable) dropEvent
.getTransferable();
file = (File) transferable.getItemId();
} else if (dropEvent.getTransferable()
.getSourceComponent() instanceof FileIcon) {
FileIcon draggedIcon = (FileIcon) dropEvent
.getTransferable().getSourceComponent();
file = draggedIcon.file;
}
setParent(file, folder);
}
};
tree1.setDropHandler(dropHandler);
Handler actionHandler = new Handler() {
private Action[] actions = new Action[] { new Action("Remove") };
@Override
public void handleAction(Action action, Object sender,
Object target) {
ContainerHierarchicalWrapper containerDataSource = (ContainerHierarchicalWrapper) tree1
.getContainerDataSource();
containerDataSource.removeItemRecursively(target);
}
@Override
public Action[] getActions(Object target, Object sender) {
return actions;
}
};
tree1.addActionHandler(actionHandler);
tree1.addListener(new Property.ValueChangeListener() {
@Override
public void valueChange(ValueChangeEvent event) {
Object value = event.getProperty().getValue();
if (value != null && !(value instanceof Folder)) {
value = tree1.getParent(value);
}
FolderView folderView = FolderView.get((Folder) value);
sp.setSecondComponent(folderView);
folderView.reload();
}
});
l.addComponent(tree1);
sp.setSecondComponent(FolderView.get(null));
getLayout().setSizeFull();
getLayout().addComponent(sp);
TestUtils.injectCSS(getLayout().getUI(), ""
+ ".v-tree .v-icon {height:16px;} "
+ ".v-tree-node-caption-drag-top {/*border-top: none;*/} "
+ ".v-tree-node-caption-drag-bottom {border-bottom: none ;} "
+ ".v-tree-node-caption-drag-center {background-color: transparent;}"
+ ".v-tree-node-caption-dragfolder { background-color: cyan;} ");
}
private final static ThemeResource FOLDER = new ThemeResource(
"../runo/icons/64/folder.png");
private final static ThemeResource DOC = new ThemeResource(
"../runo/icons/64/document.png");
public static class File {
private Resource icon = DOC;
private String name;
private ByteArrayOutputStream bas;
private String type;
public File(String fileName) {
name = fileName;
}
public File(String fileName, ByteArrayOutputStream bas) {
this(fileName);
this.bas = bas;
}
public void setIcon(Resource icon) {
this.icon = icon;
}
public Resource getIcon() {
return icon;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public Resource getResource() {
StreamSource streamSource = new StreamSource() {
@Override
public InputStream getStream() {
if (bas != null) {
byte[] byteArray = bas.toByteArray();
return new ByteArrayInputStream(byteArray);
}
return null;
}
};
return new StreamResource(streamSource, getName());
}
}
public static class Folder extends File {
public Folder(String fileName) {
super(fileName);
setIcon(FOLDER);
}
}
@Override
protected String getDescription() {
return "dd: tree and web desktop tests. FF36 supports draggin files from client side. (try dragging png image + double click) TODO more files, auto-opening folders";
}
@Override
protected Integer getTicketNumber() {
return 119;
}
private void openFile(File file) {
// ATM supports only images.
if (file.getType().equals("image/png")) {
Embedded embedded = new Embedded(file.getName(),
file.getResource());
VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
Window w = new Window(file.getName(), layout);
layout.addComponent(embedded);
layout.setSizeUndefined();
getMainWindow().addWindow(w);
} else if (file.getType().equals("text/csv")) {
showSpreadsheet(file);
}
}
private void showSpreadsheet(File file) {
// ApplicationResource resource = (ApplicationResource)
// file.getResource();
String string = new String(file.bas.toByteArray());
String[] rows = string.split("\n");
String[] cols = rows[0].split(",");
Table table = new Table();
for (String string2 : cols) {
// String col =
string2.replaceAll("\"", ""); // remove surrounding ""
table.addContainerProperty(string2, String.class, "");
}
for (int i = 1; i < rows.length; i++) {
String[] split = rows[i].split(",");
table.addItem(split, "" + i);
}
VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
Window w = new Window(file.getName(), layout);
layout.setSizeUndefined();
table.setEditable(true);
layout.addComponent(table);
getMainWindow().addWindow(w);
}
static class FolderView extends DragAndDropWrapper implements DropHandler {
static final HashMap<Folder, FolderView> views = new HashMap<>();
public static FolderView get(Folder f) {
FolderView folder2 = views.get(f);
if (folder2 == null) {
folder2 = new FolderView(f);
views.put(f, folder2);
}
return folder2;
}
private Folder folder;
private AbsoluteLayout l;
private int x;
private int y;
private FolderView(Folder f) {
super(new AbsoluteLayout());
l = (AbsoluteLayout) getCompositionRoot();
setSizeFull();
l.setSizeFull();
folder = f;
setDropHandler(this);
}
@Override
public void attach() {
reload();
super.attach();
}
@SuppressWarnings("static-access")
void reload() {
Collection<?> children = folder == null
? DDTest6.get().tree1.rootItemIds()
: DDTest6.get().tree1.getChildren(folder);
if (children == null) {
l.removeAllComponents();
return;
} else {
// make modifiable
children = new HashSet<Object>(children);
}
Set<Component> removed = new HashSet<>();
for (Iterator<Component> componentIterator = l
.getComponentIterator(); componentIterator.hasNext();) {
FileIcon next = (FileIcon) componentIterator.next();
if (!children.contains(next.file)) {
removed.add(next);
} else {
children.remove(next.file);
}
}
for (Component component : removed) {
l.removeComponent(component);
}
for (Object object : children) {
FileIcon fileIcon = new FileIcon((File) object);
l.addComponent(fileIcon);
ComponentPosition position = l.getPosition(fileIcon);
position.setTop(Float.valueOf((y++ / 5) % 5 * 100),
UNITS_PIXELS);
position.setLeft(Float.valueOf(x++ % 5 * 100), UNITS_PIXELS);
}
}
@Override
@SuppressWarnings("static-access")
public void drop(DragAndDropEvent dropEvent) {
if (dropEvent.getTransferable()
.getSourceComponent() instanceof FileIcon) {
// update the position
DragAndDropWrapper.WrapperTransferable transferable = (WrapperTransferable) dropEvent
.getTransferable();
MouseEventDetails mouseDownEvent = transferable
.getMouseDownEvent();
WrapperTargetDetails dropTargetDetails = (WrapperTargetDetails) dropEvent
.getTargetDetails();
MouseEventDetails mouseEvent = dropTargetDetails
.getMouseEvent();
int deltaX = mouseEvent.getClientX()
- mouseDownEvent.getClientX();
int deltaY = mouseEvent.getClientY()
- mouseDownEvent.getClientY();
ComponentPosition position = l
.getPosition(transferable.getSourceComponent());
position.setTop(position.getTopValue() + deltaY, UNITS_PIXELS);
position.setLeft(position.getLeftValue() + deltaX,
UNITS_PIXELS);
} else if (dropEvent.getTransferable()
.getSourceComponent() == tree1) {
// dragged something from tree to the folder shown
File draggedFile = (File) ((DataBoundTransferable) dropEvent
.getTransferable()).getItemId();
DDTest6.get().setParent(draggedFile, folder);
} else {
// expecting this to be an html5 drag
WrapperTransferable tr = (WrapperTransferable) dropEvent
.getTransferable();
Html5File[] files2 = tr.getFiles();
if (files2 != null) {
for (Html5File html5File : files2) {
String fileName = html5File.getFileName();
// int bytes = html5File.getFileSize();
final ByteArrayOutputStream bas = new ByteArrayOutputStream();
StreamVariable streamVariable = new StreamVariable() {
@Override
public OutputStream getOutputStream() {
return bas;
}
@Override
public boolean listenProgress() {
return false;
}
@Override
public void onProgress(
StreamingProgressEvent event) {
}
@Override
public void streamingStarted(
StreamingStartEvent event) {
}
@Override
public void streamingFinished(
StreamingEndEvent event) {
}
@Override
public void streamingFailed(
StreamingErrorEvent event) {
}
@Override
public boolean isInterrupted() {
return false;
}
};
html5File.setStreamVariable(streamVariable);
File file = new File(fileName, bas);
file.setType(html5File.getType());
// FF don't know csv
if (fileName.endsWith(".csv")) {
file.setType("text/csv");
}
DDTest6.get().fs1.addBean(file);
DDTest6.get().tree1.setChildrenAllowed(file, false);
DDTest6.get().setParent(file, folder);
}
}
}
}
@Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
}
static class FileIcon extends DragAndDropWrapper {
private final File file;
private CssLayout l;
public FileIcon(final File file) {
super(new CssLayout());
l = (CssLayout) getCompositionRoot();
setWidth(null);
l.setWidth(null);
setDragStartMode(DragStartMode.WRAPPER); // drag all contained
// components, not just the
// one on it started
this.file = file;
Resource icon2 = file.getIcon();
String name = file.getName();
l.addComponent(new Embedded(null, icon2));
l.addComponent(new Label(name));
l.addLayoutClickListener(new LayoutClickListener() {
@Override
@SuppressWarnings("static-access")
public void layoutClick(LayoutClickEvent event) {
if (event.isDoubleClick()) {
if (file instanceof Folder) {
get().tree1.setValue(file);
} else {
String type = file.getType();
if (canDisplay(type)) {
DDTest6.get().openFile(file);
}
}
}
}
String[] knownTypes = new String[] { "image/png", "text/csv" };
private boolean canDisplay(String type) {
if (type != null) {
for (String t : knownTypes) {
if (t.equals(type)) {
return true;
}
}
}
return false;
}
});
if (file instanceof Folder) {
setDropHandler(new DropHandler() {
@Override
public AcceptCriterion getAcceptCriterion() {
return new Not(SourceIsTarget.get());
}
@Override
public void drop(DragAndDropEvent dropEvent) {
File f = null;
if (dropEvent.getTransferable()
.getSourceComponent() instanceof FileIcon) {
FileIcon new_name = (FileIcon) dropEvent
.getTransferable().getSourceComponent();
f = new_name.file;
} else if (dropEvent.getTransferable()
.getSourceComponent() == tree1) {
f = (File) ((DataBoundTransferable) dropEvent
.getTransferable()).getItemId();
}
if (f != null) {
get().setParent(f, (Folder) FileIcon.this.file);
}
}
});
}
}
}
static DDTest6 get() {
return instance;
}
public void setParent(File file, Folder newParent) {
tree1.setParent(file, newParent);
if (sp.getSecondComponent() instanceof FolderView) {
FolderView view = (FolderView) sp.getSecondComponent();
view.reload();
}
}
}