You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DDTest6.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. package com.vaadin.tests.dd;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. import java.util.Collection;
  8. import java.util.HashMap;
  9. import java.util.HashSet;
  10. import java.util.Iterator;
  11. import java.util.Set;
  12. import com.vaadin.data.Property;
  13. import com.vaadin.data.Property.ValueChangeEvent;
  14. import com.vaadin.data.util.BeanItemContainer;
  15. import com.vaadin.data.util.ContainerHierarchicalWrapper;
  16. import com.vaadin.event.Action;
  17. import com.vaadin.event.DataBoundTransferable;
  18. import com.vaadin.event.Action.Handler;
  19. import com.vaadin.event.LayoutEvents.LayoutClickEvent;
  20. import com.vaadin.event.LayoutEvents.LayoutClickListener;
  21. import com.vaadin.event.dd.DragAndDropEvent;
  22. import com.vaadin.event.dd.DropHandler;
  23. import com.vaadin.event.dd.acceptcriteria.AcceptAll;
  24. import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
  25. import com.vaadin.event.dd.acceptcriteria.IsSameSourceAndTarget;
  26. import com.vaadin.event.dd.acceptcriteria.Not;
  27. import com.vaadin.terminal.ApplicationResource;
  28. import com.vaadin.terminal.Resource;
  29. import com.vaadin.terminal.StreamResource;
  30. import com.vaadin.terminal.ThemeResource;
  31. import com.vaadin.terminal.StreamResource.StreamSource;
  32. import com.vaadin.terminal.gwt.client.MouseEventDetails;
  33. import com.vaadin.tests.components.TestBase;
  34. import com.vaadin.tests.util.TestUtils;
  35. import com.vaadin.ui.AbsoluteLayout;
  36. import com.vaadin.ui.Component;
  37. import com.vaadin.ui.CssLayout;
  38. import com.vaadin.ui.DragAndDropWrapper;
  39. import com.vaadin.ui.Embedded;
  40. import com.vaadin.ui.Label;
  41. import com.vaadin.ui.SplitPanel;
  42. import com.vaadin.ui.Table;
  43. import com.vaadin.ui.Tree;
  44. import com.vaadin.ui.Window;
  45. import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
  46. import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable.Html5File;
  47. import com.vaadin.ui.Tree.TreeDragMode;
  48. import com.vaadin.ui.Tree.TreeDropTargetDetails;
  49. import com.vaadin.ui.Upload.Receiver;
  50. public class DDTest6 extends TestBase {
  51. java.util.Random r = new java.util.Random(1);
  52. File[] files = new File[] { new Folder("Docs"), new Folder("Music"),
  53. new Folder("Images"), new File("document.doc"),
  54. new File("song.mp3"), new File("photo.jpg") };
  55. private DropHandler dh;
  56. private static Tree tree1;
  57. private SplitPanel sp;
  58. private BeanItemContainer<File> fs1;
  59. private static int count;
  60. private static DDTest6 instance;
  61. @Override
  62. protected void setup() {
  63. instance = this; // Note, test only works with single app per server if
  64. // get()
  65. // not converted to thread local
  66. sp = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL);
  67. sp.setSplitPosition(20);
  68. CssLayout l = new CssLayout();
  69. sp.setFirstComponent(l);
  70. tree1 = new Tree("Volume 1");
  71. tree1.setImmediate(true);
  72. fs1 = new BeanItemContainer<File>(File.class);
  73. tree1.setContainerDataSource(fs1);
  74. for (int i = 0; i < files.length; i++) {
  75. fs1.addBean(files[i]);
  76. if (files[i] instanceof Folder) {
  77. tree1.setChildrenAllowed(files[i], true);
  78. } else {
  79. tree1.setChildrenAllowed(files[i], false);
  80. }
  81. if (i >= files.length / 2) {
  82. tree1.setParent(files[i], files[i - files.length / 2]);
  83. }
  84. }
  85. tree1.setItemCaptionPropertyId("name");
  86. tree1.setItemIconPropertyId("icon");
  87. tree1.setDragMode(TreeDragMode.NODE);
  88. DropHandler dropHandler = new DropHandler() {
  89. public AcceptCriterion getAcceptCriterion() {
  90. return AcceptAll.get();
  91. }
  92. public void drop(DragAndDropEvent dropEvent) {
  93. File file = null;
  94. Folder folder = null;
  95. TreeDropTargetDetails dropTargetData = (TreeDropTargetDetails) dropEvent
  96. .getDropTargetDetails();
  97. folder = (Folder) dropTargetData.getItemIdInto();
  98. if (dropEvent.getTransferable() instanceof DataBoundTransferable) {
  99. DataBoundTransferable transferable = (DataBoundTransferable) dropEvent
  100. .getTransferable();
  101. file = (File) transferable.getItemId();
  102. } else if (dropEvent.getTransferable().getSourceComponent() instanceof FileIcon) {
  103. FileIcon draggedIcon = (FileIcon) dropEvent
  104. .getTransferable().getSourceComponent();
  105. file = draggedIcon.file;
  106. }
  107. setParent(file, folder);
  108. }
  109. };
  110. tree1.setDropHandler(dropHandler);
  111. Handler actionHandler = new Handler() {
  112. private Action[] actions = new Action[] { new Action("Remove") };
  113. public void handleAction(Action action, Object sender, Object target) {
  114. ContainerHierarchicalWrapper containerDataSource = (ContainerHierarchicalWrapper) tree1
  115. .getContainerDataSource();
  116. containerDataSource.removeItemRecursively(target);
  117. }
  118. public Action[] getActions(Object target, Object sender) {
  119. return actions;
  120. }
  121. };
  122. tree1.addActionHandler(actionHandler);
  123. tree1.addListener(new Property.ValueChangeListener() {
  124. public void valueChange(ValueChangeEvent event) {
  125. Object value = event.getProperty().getValue();
  126. if (value != null && !(value instanceof Folder)) {
  127. value = tree1.getParent(value);
  128. }
  129. FolderView folderView = FolderView.get((Folder) value);
  130. sp.setSecondComponent(folderView);
  131. folderView.reload();
  132. }
  133. });
  134. l.addComponent(tree1);
  135. sp.setSecondComponent(FolderView.get(null));
  136. getLayout().setSizeFull();
  137. getLayout().addComponent(sp);
  138. TestUtils
  139. .injectCSS(
  140. getLayout().getWindow(),
  141. ""
  142. + ".v-tree .v-icon {height:16px;} "
  143. + ".v-tree-node-caption-drag-top {/*border-top: none;*/} "
  144. + ".v-tree-node-caption-drag-bottom {border-bottom: none ;} "
  145. + ".v-tree-node-caption-drag-center {background-color: transparent;}"
  146. + ".v-tree-node-caption-dragfolder { background-color: cyan;} ");
  147. }
  148. private final static ThemeResource FOLDER = new ThemeResource(
  149. "../runo/icons/64/folder.png");
  150. private final static ThemeResource DOC = new ThemeResource(
  151. "../runo/icons/64/document.png");
  152. public static class File {
  153. private Resource icon = DOC;
  154. private String name;
  155. private ByteArrayOutputStream bas;
  156. private String type;
  157. public File(String fileName) {
  158. name = fileName;
  159. }
  160. public File(String fileName, ByteArrayOutputStream bas) {
  161. this(fileName);
  162. this.bas = bas;
  163. }
  164. public void setIcon(Resource icon) {
  165. this.icon = icon;
  166. }
  167. public Resource getIcon() {
  168. return icon;
  169. }
  170. public void setName(String name) {
  171. this.name = name;
  172. }
  173. public String getName() {
  174. return name;
  175. }
  176. public void setType(String type) {
  177. this.type = type;
  178. }
  179. public String getType() {
  180. return type;
  181. }
  182. public Resource getResource() {
  183. StreamSource streamSource = new StreamSource() {
  184. public InputStream getStream() {
  185. if (bas != null) {
  186. byte[] byteArray = bas.toByteArray();
  187. return new ByteArrayInputStream(byteArray);
  188. }
  189. // TODO Auto-generated method stub
  190. return null;
  191. }
  192. };
  193. return new StreamResource(streamSource, getName(), DDTest6.get());
  194. }
  195. }
  196. public static class Folder extends File {
  197. public Folder(String fileName) {
  198. super(fileName);
  199. setIcon(FOLDER);
  200. }
  201. }
  202. @Override
  203. protected String getDescription() {
  204. 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";
  205. }
  206. @Override
  207. protected Integer getTicketNumber() {
  208. return 119;
  209. }
  210. private void openFile(File file) {
  211. // ATM supports only images.
  212. if (file.getType().equals("image/png")) {
  213. Embedded embedded = new Embedded(file.getName(), file.getResource());
  214. Window w = new Window(file.getName());
  215. w.addComponent(embedded);
  216. w.getContent().setSizeUndefined();
  217. getMainWindow().addWindow(w);
  218. } else if (file.getType().equals("text/csv")) {
  219. showSpreadsheet(file);
  220. }
  221. }
  222. private void showSpreadsheet(File file) {
  223. ApplicationResource resource = (ApplicationResource) file.getResource();
  224. String string = new String(file.bas.toByteArray());
  225. String[] rows = string.split("\n");
  226. String[] cols = rows[0].split(",");
  227. Table table = new Table();
  228. for (String string2 : cols) {
  229. String col = string2.replaceAll("\"", ""); // remove surrounding ""
  230. table.addContainerProperty(string2, String.class, "");
  231. }
  232. for (int i = 1; i < rows.length; i++) {
  233. String[] split = rows[i].split(",");
  234. table.addItem(split, "" + i);
  235. }
  236. Window w = new Window(file.getName());
  237. w.getContent().setSizeUndefined();
  238. table.setEditable(true);
  239. w.addComponent(table);
  240. getMainWindow().addWindow(w);
  241. // TODO saving would be nice demo
  242. }
  243. static class FolderView extends DragAndDropWrapper implements DropHandler {
  244. static final HashMap<Folder, FolderView> views = new HashMap<Folder, FolderView>();
  245. public static FolderView get(Folder f) {
  246. FolderView folder2 = views.get(f);
  247. if (folder2 == null) {
  248. folder2 = new FolderView(f);
  249. views.put(f, folder2);
  250. }
  251. return folder2;
  252. }
  253. private Folder folder;
  254. private AbsoluteLayout l;
  255. private int x;
  256. private int y;
  257. private FolderView(Folder f) {
  258. super(new AbsoluteLayout());
  259. l = (AbsoluteLayout) getCompositionRoot();
  260. setSizeFull();
  261. l.setSizeFull();
  262. folder = f;
  263. setDropHandler(this);
  264. }
  265. @Override
  266. public void attach() {
  267. reload();
  268. super.attach();
  269. }
  270. void reload() {
  271. Collection<?> children = folder == null ? DDTest6.get().tree1
  272. .rootItemIds() : DDTest6.get().tree1.getChildren(folder);
  273. if (children == null) {
  274. l.removeAllComponents();
  275. return;
  276. } else {
  277. // make modifiable
  278. children = new HashSet<Object>(children);
  279. }
  280. Set<Component> removed = new HashSet<Component>();
  281. for (Iterator<Component> componentIterator = l
  282. .getComponentIterator(); componentIterator.hasNext();) {
  283. FileIcon next = (FileIcon) componentIterator.next();
  284. if (!children.contains(next.file)) {
  285. removed.add(next);
  286. } else {
  287. children.remove(next.file);
  288. }
  289. }
  290. for (Component component : removed) {
  291. l.removeComponent(component);
  292. }
  293. for (Object object : children) {
  294. FileIcon fileIcon = new FileIcon((File) object);
  295. l.addComponent(fileIcon);
  296. ComponentPosition position = l.getPosition(fileIcon);
  297. position.setTop((y++ / 5) % 5 * 100, UNITS_PIXELS);
  298. position.setLeft(x++ % 5 * 100, UNITS_PIXELS);
  299. }
  300. }
  301. public void drop(DragAndDropEvent dropEvent) {
  302. if (dropEvent.getTransferable().getSourceComponent() instanceof FileIcon) {
  303. // update the position
  304. DragAndDropWrapper.WrapperTransferable transferable = (WrapperTransferable) dropEvent
  305. .getTransferable();
  306. MouseEventDetails mouseDownEvent = transferable
  307. .getMouseDownEvent();
  308. WrapperDropDetails dropTargetDetails = (WrapperDropDetails) dropEvent
  309. .getDropTargetDetails();
  310. MouseEventDetails mouseEvent = dropTargetDetails
  311. .getMouseEvent();
  312. int deltaX = mouseEvent.getClientX()
  313. - mouseDownEvent.getClientX();
  314. int deltaY = mouseEvent.getClientY()
  315. - mouseDownEvent.getClientY();
  316. ComponentPosition position = l.getPosition(transferable
  317. .getSourceComponent());
  318. position.setTop(position.getTopValue() + deltaY, UNITS_PIXELS);
  319. position
  320. .setLeft(position.getLeftValue() + deltaX, UNITS_PIXELS);
  321. } else if (dropEvent.getTransferable().getSourceComponent() == tree1) {
  322. // dragged something from tree to the folder shown
  323. File draggedFile = (File) ((DataBoundTransferable) dropEvent
  324. .getTransferable()).getItemId();
  325. DDTest6.get().setParent(draggedFile, folder);
  326. } else {
  327. // expecting this to be an html5 drag
  328. WrapperTransferable tr = (WrapperTransferable) dropEvent
  329. .getTransferable();
  330. Html5File[] files2 = tr.getFiles();
  331. if (files2 != null) {
  332. for (Html5File html5File : files2) {
  333. String fileName = html5File.getFileName();
  334. // int bytes = html5File.getFileSize();
  335. final ByteArrayOutputStream bas = new ByteArrayOutputStream() {
  336. @Override
  337. public void close() throws IOException {
  338. super.close();
  339. }
  340. };
  341. Receiver receiver = new Receiver() {
  342. public OutputStream receiveUpload(String filename,
  343. String MIMEType) {
  344. return bas;
  345. }
  346. };
  347. html5File.setReceiver(receiver);
  348. File file = new File(fileName, bas);
  349. file.setType(html5File.getType());
  350. // FF don't know csv
  351. if (fileName.endsWith(".csv")) {
  352. file.setType("text/csv");
  353. }
  354. DDTest6.get().fs1.addBean(file);
  355. DDTest6.get().tree1.setChildrenAllowed(file, false);
  356. DDTest6.get().setParent(file, folder);
  357. }
  358. }
  359. }
  360. }
  361. public AcceptCriterion getAcceptCriterion() {
  362. return AcceptAll.get();
  363. }
  364. }
  365. static class FileIcon extends DragAndDropWrapper {
  366. private final File file;
  367. private CssLayout l;
  368. public FileIcon(final File file) {
  369. super(new CssLayout());
  370. l = (CssLayout) getCompositionRoot();
  371. setWidth(null);
  372. l.setWidth(null);
  373. setDragStartMode(DragStartMode.WRAPPER); // drag all contained
  374. // components, not just the
  375. // one on it started
  376. this.file = file;
  377. Resource icon2 = file.getIcon();
  378. String name = file.getName();
  379. l.addComponent(new Embedded(null, icon2));
  380. l.addComponent(new Label(name));
  381. l.addListener(new LayoutClickListener() {
  382. public void layoutClick(LayoutClickEvent event) {
  383. if (event.isDoubleClick()) {
  384. if (file instanceof Folder) {
  385. get().tree1.setValue(file);
  386. } else {
  387. String type = file.getType();
  388. if (canDisplay(type)) {
  389. DDTest6.get().openFile(file);
  390. }
  391. }
  392. }
  393. }
  394. String[] knownTypes = new String[] { "image/png", "text/csv" };
  395. private boolean canDisplay(String type) {
  396. if (type != null) {
  397. for (String t : knownTypes) {
  398. if (t.equals(type)) {
  399. return true;
  400. }
  401. }
  402. }
  403. return false;
  404. }
  405. });
  406. if (file instanceof Folder) {
  407. setDropHandler(new DropHandler() {
  408. public AcceptCriterion getAcceptCriterion() {
  409. return new Not(IsSameSourceAndTarget.get());
  410. }
  411. public void drop(DragAndDropEvent dropEvent) {
  412. File f = null;
  413. if (dropEvent.getTransferable().getSourceComponent() instanceof FileIcon) {
  414. FileIcon new_name = (FileIcon) dropEvent
  415. .getTransferable().getSourceComponent();
  416. f = new_name.file;
  417. } else if (dropEvent.getTransferable()
  418. .getSourceComponent() == tree1) {
  419. f = (File) ((DataBoundTransferable) dropEvent
  420. .getTransferable()).getItemId();
  421. }
  422. if (f != null) {
  423. get().setParent(f, (Folder) FileIcon.this.file);
  424. }
  425. }
  426. });
  427. }
  428. }
  429. }
  430. static DDTest6 get() {
  431. return instance;
  432. }
  433. public void setParent(File file, Folder newParent) {
  434. tree1.setParent(file, newParent);
  435. if (sp.getSecondComponent() instanceof FolderView) {
  436. FolderView view = (FolderView) sp.getSecondComponent();
  437. view.reload();
  438. }
  439. }
  440. }