/*******************************************************************************
 * Copyright (c) 2000, 2005 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
 *******************************************************************************/
package org.eclipse.swt.examples.dnd;

 
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class DNDExample {
	
	private int dragOperation = 0;
	private Transfer[] dragTypes = new Transfer[0];
	private Control dragControl;
	private int dragControlType = 0;
	private DragSource dragSource;
	private String dragDataText;
	private String dragDataRTF;
	private String dragDataHTML;
	private String[] dragDataFiles;
	private List fileList;
	private boolean dragEnabled = false;
	
	private int dropOperation = 0;
	private int dropFeedback = 0;
	private int dropDefaultOperation = 0;
	private Transfer[] dropTypes = new Transfer[0];
	private DropTarget dropTarget;
	private Control dropControl;
	private int dropControlType = 0;
	private Composite defaultParent;
	private boolean dropEnabled = false;
	
	private Text dragConsole;
	private boolean dragEventDetail = false;
	private Text dropConsole;
	private boolean dropEventDetail = false;
	
	private static final int BUTTON_TOGGLE = 0;
	private static final int BUTTON_RADIO = 1;
	private static final int BUTTON_CHECK = 2;
	private static final int CANVAS = 3;
	private static final int LABEL = 4;
	private static final int LIST = 5;
	private static final int TABLE = 6;
	private static final int TREE = 7;
	private static final int TEXT = 8;
	private static final int STYLED_TEXT = 9;
	
public static void main(String[] args) {
	Display display = new Display();
	DNDExample example = new DNDExample();
	example.open(display);
	display.dispose();
}

private void addDragTransfer(Transfer transfer){
	Transfer[] newTypes = new Transfer[dragTypes.length + 1];
	System.arraycopy(dragTypes, 0, newTypes, 0, dragTypes.length);
	newTypes[dragTypes.length] = transfer;
	dragTypes = newTypes;
	if (dragSource != null) {
		dragSource.setTransfer(dragTypes);
	}
}

private void addDropTransfer(Transfer transfer){
	Transfer[] newTypes = new Transfer[dropTypes.length + 1];
	System.arraycopy(dropTypes, 0, newTypes, 0, dropTypes.length);
	newTypes[dropTypes.length] = transfer;
	dropTypes = newTypes;
	if (dropTarget != null) {
		dropTarget.setTransfer(dropTypes);
	}
}

private void createDragOperations(Composite parent) {
	parent.setLayout(new RowLayout(SWT.VERTICAL));
	final Button moveButton = new Button(parent, SWT.CHECK);
	moveButton.setText("DND.DROP_MOVE");
	moveButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dragOperation |= DND.DROP_MOVE;			
			} else {
				dragOperation = dragOperation &~DND.DROP_MOVE;
				if (dragOperation == 0) {
					dragOperation = DND.DROP_MOVE;
					moveButton.setSelection(true);
				}
			}
			if (dragEnabled) {
				createDragSource();
			}
		}
	});
	

	Button copyButton = new Button(parent, SWT.CHECK);
	copyButton.setText("DND.DROP_COPY");
	copyButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dragOperation |= DND.DROP_COPY;			
			} else {
				dragOperation = dragOperation &~DND.DROP_COPY;
				if (dragOperation == 0) {
					dragOperation = DND.DROP_MOVE;
					moveButton.setSelection(true);
				}
			}
			if (dragEnabled) {
				createDragSource();
			}
		}
	});

	Button linkButton = new Button(parent, SWT.CHECK);
	linkButton.setText("DND.DROP_LINK");
	linkButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dragOperation |= DND.DROP_LINK;			
			} else {
				dragOperation = dragOperation &~DND.DROP_LINK;
				if (dragOperation == 0) {
					dragOperation = DND.DROP_MOVE;
					moveButton.setSelection(true);
				}
			}
			if (dragEnabled) {
				createDragSource();
			}
		}
	});
	
	//initialize state
	moveButton.setSelection(true);
	copyButton.setSelection(true);
	linkButton.setSelection(true);
	dragOperation |= DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
}

private void createDragSource() {
	if (dragSource != null) dragSource.dispose();
	dragSource = new DragSource(dragControl, dragOperation);
	dragSource.setTransfer(dragTypes);
	dragSource.addDragListener(new DragSourceListener() {
		public void dragFinished(org.eclipse.swt.dnd.DragSourceEvent event) {
			dragConsole.append(">>dragFinished\n");
			printEvent(event);
			dragDataText = dragDataRTF = dragDataHTML = null;
			dragDataFiles = null;
			if (event.detail == DND.DROP_MOVE) {
				switch(dragControlType) {
					case BUTTON_CHECK:
					case BUTTON_TOGGLE:
					case BUTTON_RADIO: {
						Button b = (Button)dragControl;
						b.setText("");
						break;
					}
					case STYLED_TEXT: {
						StyledText text = (StyledText)dragControl;
						text.insert("");
						break;
					}
					case TABLE: {
						Table table = (Table)dragControl;
						TableItem[] items = table.getSelection();
						for (int i = 0; i < items.length; i++) {
							items[i].dispose();
						}
						break;
					}
					case TEXT: {
						Text text = (Text)dragControl;
						text.insert("");
						break;
					}
					case TREE: {
						Tree tree = (Tree)dragControl;
						TreeItem[] items = tree.getSelection();
						for (int i = 0; i < items.length; i++) {
							items[i].dispose();
						}
						break;
					}
					case CANVAS: {
						dragControl.setData("STRINGS", null);
						dragControl.redraw();
						break;
					}
					case LABEL: {
						Label label = (Label)dragControl;
						label.setText("");
						break;
					}
					case LIST: {
						List list = (List)dragControl;
						int[] indices = list.getSelectionIndices();
						list.remove(indices);
						break;
					}
				}
			}
		}
		public void dragSetData(org.eclipse.swt.dnd.DragSourceEvent event) {
			dragConsole.append(">>dragSetData\n");
			printEvent(event);
			if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
				event.data = dragDataText;
			}
			if (RTFTransfer.getInstance().isSupportedType(event.dataType)) {
				event.data = dragDataRTF;
			}
			if (HTMLTransfer.getInstance().isSupportedType(event.dataType)) {
				event.data = dragDataHTML;
			}
			if (FileTransfer.getInstance().isSupportedType(event.dataType)) {
				event.data = dragDataFiles;
			}
		}
		public void dragStart(org.eclipse.swt.dnd.DragSourceEvent event) {
			dragConsole.append(">>dragStart\n");
			printEvent(event);
			dragDataFiles = fileList.getItems();
			switch(dragControlType) {
				case BUTTON_CHECK:
				case BUTTON_TOGGLE:
				case BUTTON_RADIO: {
					Button b = (Button)dragControl;
					dragDataText = b.getSelection() ? "true" : "false";
					break;
				}
				case STYLED_TEXT: {
					StyledText text = (StyledText)dragControl;
					String s = text.getSelectionText();
					if (s.length() == 0) {
						event.doit = false;
					} else {
						dragDataText = s;
					}
					break;
				}
				case TABLE: {
					Table table = (Table)dragControl;
					TableItem[] items = table.getSelection();
					if (items.length == 0) {
						event.doit = false;
					} else {
						StringBuffer buffer = new StringBuffer();
						for (int i = 0; i < items.length; i++) {
							buffer.append(items[i].getText());
							if (items.length > 1 && i < items.length - 1) {
								buffer.append("\n");
							}
						}
						dragDataText = buffer.toString();
					}
					break;
				}
				case TEXT: {
					Text text = (Text)dragControl;
					String s = text.getSelectionText();
					if (s.length() == 0) {
						event.doit = false;
					} else {
						dragDataText = s;
					}
					break;
				}
				case TREE: {
					Tree tree = (Tree)dragControl;
					TreeItem[] items = tree.getSelection();
					if (items.length == 0) {
						event.doit = false;
					} else {
						StringBuffer buffer = new StringBuffer();
						for (int i = 0; i < items.length; i++) {
							buffer.append(items[i].getText());
							if (items.length > 1 && i < items.length - 1) {
								buffer.append("\n");
							}
						}
						dragDataText = buffer.toString();
					}
					break;
				}
				case CANVAS: {
					String[] strings = (String[])dragControl.getData("STRINGS");
					if (strings == null || strings.length == 0) {
						event.doit = false;
					} else {
						StringBuffer buffer = new StringBuffer();
						for (int i = 0; i < strings.length; i++) {
							buffer.append(strings[i]);
							if (strings.length > 1 && i < strings.length - 1) {
								buffer.append("\n");
							}
						}
						dragDataText = buffer.toString();
					}
					break;
				}
				case LABEL: {
					Label label = (Label)dragControl;
					String string = label.getText();
					if (string.length() == 0) {
						event.doit = false;
					} else {
						dragDataText = string;
					}
					break;
				}
				case LIST: {
					List list = (List)dragControl;
					String[] selection = list.getSelection();
					if (selection.length == 0) {
						event.doit = false;
					} else {
						StringBuffer buffer = new StringBuffer();
						for (int i = 0; i < selection.length; i++) {
							buffer.append(selection[i]);
							if (selection.length > 1 && i < selection.length - 1) {
								buffer.append("\n");
							}
						}
						dragDataText = buffer.toString();
					}
					break;
				}
				default:
					throw new SWTError(SWT.ERROR_NOT_IMPLEMENTED);
			}
			if (dragDataText != null) {
				dragDataRTF = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\cf1\\b "+dragDataText+"}";
				dragDataHTML = "<b>"+dragDataText+"</b>";
			}
			
			for (int i = 0; i < dragTypes.length; i++) {
				if (dragTypes[i] instanceof TextTransfer && dragDataText == null) {
					event.doit = false;
				}
				if (dragTypes[i] instanceof RTFTransfer && dragDataRTF == null) {
					event.doit = false;
				}
				if (dragTypes[i] instanceof HTMLTransfer && dragDataHTML == null) {
					event.doit = false;
				}
				if (dragTypes[i] instanceof FileTransfer && (dragDataFiles == null || dragDataFiles.length == 0)) {
					event.doit = false;
				}
			}
		}
	});
}

private void createDragTypes(Composite parent) {
	parent.setLayout(new GridLayout());
	Button textButton = new Button(parent, SWT.CHECK);
	textButton.setText("Text Transfer");
	textButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDragTransfer(TextTransfer.getInstance());			
			} else {
				removeDragTransfer(TextTransfer.getInstance());
			}
		}
	});
	
	Button b = new Button(parent, SWT.CHECK);
	b.setText("RTF Transfer");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDragTransfer(RTFTransfer.getInstance());			
			} else {
				removeDragTransfer(RTFTransfer.getInstance());
			}
		}
	});
	
	b = new Button(parent, SWT.CHECK);
	b.setText("HTML Transfer");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDragTransfer(HTMLTransfer.getInstance());			
			} else {
				removeDragTransfer(HTMLTransfer.getInstance());
			}
		}
	});
	
	
	b = new Button(parent, SWT.CHECK);
	b.setText("File Transfer");
	b.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDragTransfer(FileTransfer.getInstance());			
			} else {
				removeDragTransfer(FileTransfer.getInstance());
			}
		}
	});
	b = new Button(parent, SWT.PUSH);
	b.setText("Select File(s)");
	b.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			FileDialog dialog = new FileDialog(fileList.getShell(), SWT.OPEN | SWT.MULTI);
			String result = dialog.open();
			if (result != null && result.length() > 0){
				fileList.removeAll();
				String separator = System.getProperty("file.separator");
				String path = dialog.getFilterPath();
				String[] names = dialog.getFileNames();
				for (int i = 0; i < names.length; i++) {
					fileList.add(path+separator+names[i]);
				}
			}
		}
	});
	fileList = new List(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
	GridData data = new GridData();
	data.grabExcessHorizontalSpace = true;
	data.horizontalAlignment = GridData.FILL;
	data.verticalAlignment = GridData.BEGINNING;
	fileList.setLayoutData(data);
	
	// initialize state
	textButton.setSelection(true);
	addDragTransfer(TextTransfer.getInstance());
}

private void createDragWidget(Composite parent) {
	parent.setLayout(new FormLayout());
	Combo combo = new Combo(parent, SWT.READ_ONLY);
	combo.setItems(new String[] {"Toggle Button", "Radio Button", "Checkbox", "Canvas", "Label", "List", "Table", "Tree", "Text", "StyledText"});
	combo.select(LABEL);
	dragControlType = combo.getSelectionIndex();
	dragControl = createWidget(dragControlType, parent, "Drag Source");
	
	combo.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Object data = dragControl.getLayoutData();
			Composite parent = dragControl.getParent();
			dragControl.dispose();
			Combo c = (Combo)e.widget; 
			dragControlType = c.getSelectionIndex();
			dragControl = createWidget(dragControlType, parent, "Drag Source");
			dragControl.setLayoutData(data);
			if (dragEnabled) createDragSource();
			parent.layout();
		}
	});
	
	Button b = new Button(parent, SWT.CHECK);
	b.setText("DragSource");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			dragEnabled = b.getSelection();
			if (dragEnabled) {
				createDragSource();
			} else {
				if (dragSource != null){
					dragSource.dispose();
				}
				dragSource = null;
			}
		}
	});
	b.setSelection(true);
	dragEnabled = true;
	
	FormData data = new FormData();
	data.top = new FormAttachment(0, 10);
	data.bottom = new FormAttachment(combo, -10);
	data.left = new FormAttachment(0, 10);
	data.right = new FormAttachment(100, -10);
	dragControl.setLayoutData(data);
	
	data = new FormData();
	data.bottom = new FormAttachment(100, -10);
	data.left = new FormAttachment(0, 10);
	combo.setLayoutData(data);
	
	data = new FormData();
	data.bottom = new FormAttachment(100, -10);
	data.left = new FormAttachment(combo, 10);
	b.setLayoutData(data);
}

private void createDropOperations(Composite parent) {
	parent.setLayout(new RowLayout(SWT.VERTICAL));
	final Button moveButton = new Button(parent, SWT.CHECK);
	moveButton.setText("DND.DROP_MOVE");
	moveButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropOperation |= DND.DROP_MOVE;			
			} else {
				dropOperation = dropOperation & ~DND.DROP_MOVE;
				if (dropOperation == 0 || (dropDefaultOperation & DND.DROP_MOVE) != 0) {
					dropOperation |= DND.DROP_MOVE;
					moveButton.setSelection(true);
				}
			}
			if (dropEnabled) {
				createDropTarget();
			}
		}
	});
	

	final Button copyButton = new Button(parent, SWT.CHECK);
	copyButton.setText("DND.DROP_COPY");
	copyButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropOperation |= DND.DROP_COPY;			
			} else {
				dropOperation = dropOperation & ~DND.DROP_COPY;
				if (dropOperation == 0 || (dropDefaultOperation & DND.DROP_COPY) != 0) {
					dropOperation = DND.DROP_COPY;
					copyButton.setSelection(true);
				}
			}
			if (dropEnabled) {
				createDropTarget();
			}
		}
	});

	final Button linkButton = new Button(parent, SWT.CHECK);
	linkButton.setText("DND.DROP_LINK");
	linkButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropOperation |= DND.DROP_LINK;			
			} else {
				dropOperation = dropOperation & ~DND.DROP_LINK;
				if (dropOperation == 0 || (dropDefaultOperation & DND.DROP_LINK) != 0) {
					dropOperation = DND.DROP_LINK;
					linkButton.setSelection(true);
				}
			}
			if (dropEnabled) {
				createDropTarget();
			}
		}
	});
	
	Button b = new Button(parent, SWT.CHECK);
	b.setText("DND.DROP_DEFAULT");
	defaultParent = new Composite(parent, SWT.NONE);
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropOperation |= DND.DROP_DEFAULT;
				defaultParent.setVisible(true);			
			} else {
				dropOperation = dropOperation & ~DND.DROP_DEFAULT;
				defaultParent.setVisible(false);
			}
			if (dropEnabled) {
				createDropTarget();
			}
		}
	});
	
	defaultParent.setVisible(false);
	GridLayout layout = new GridLayout();
	layout.marginWidth = 20;
	defaultParent.setLayout(layout);
	Label label = new Label(defaultParent, SWT.NONE);
	label.setText("Value for default operation is:");
	b = new Button(defaultParent, SWT.RADIO);
	b.setText("DND.DROP_MOVE");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropDefaultOperation = DND.DROP_MOVE;
				dropOperation |= DND.DROP_MOVE;
				moveButton.setSelection(true);
				if (dropEnabled) {
					createDropTarget();
				}
			}
		}
	});
	
	b = new Button(defaultParent, SWT.RADIO);
	b.setText("DND.DROP_COPY");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropDefaultOperation = DND.DROP_COPY;
				dropOperation |= DND.DROP_COPY;
				copyButton.setSelection(true);
				if (dropEnabled) {
					createDropTarget();
				}
			}
		}
	});

	b = new Button(defaultParent, SWT.RADIO);
	b.setText("DND.DROP_LINK");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropDefaultOperation = DND.DROP_LINK;
				dropOperation |= DND.DROP_LINK;
				linkButton.setSelection(true);
				if (dropEnabled) {
					createDropTarget();
				}
			}
		}
	});
	
	b = new Button(defaultParent, SWT.RADIO);
	b.setText("DND.DROP_NONE");
	b.setSelection(true);
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropDefaultOperation = DND.DROP_NONE;
				dropOperation &= ~DND.DROP_DEFAULT;
				if (dropEnabled) {
					createDropTarget();
				}
			}
		}
	});
	
	// initialize state
	moveButton.setSelection(true);
	copyButton.setSelection(true);
	linkButton.setSelection(true);
	dropOperation = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
}

private void createDropTarget() {
	if (dropTarget != null) dropTarget.dispose();
	dropTarget = new DropTarget(dropControl, dropOperation);
	dropTarget.setTransfer(dropTypes);
	dropTarget.addDropListener(new DropTargetListener() {
		public void dragEnter(DropTargetEvent event) {
			dropConsole.append(">>dragEnter\n");
			printEvent(event);
			if (event.detail == DND.DROP_DEFAULT) {
				event.detail = dropDefaultOperation;
			}
			event.feedback = dropFeedback;
		}
		public void dragLeave(DropTargetEvent event) {
			dropConsole.append(">>dragLeave\n");
			printEvent(event);
		}
		public void dragOperationChanged(DropTargetEvent event) {
			dropConsole.append(">>dragOperationChanged\n");
			printEvent(event);
			if (event.detail == DND.DROP_DEFAULT) {
				event.detail = dropDefaultOperation;
			}
			event.feedback = dropFeedback;
		}
		public void dragOver(DropTargetEvent event) {
			dropConsole.append(">>dragOver\n");
			printEvent(event);
			event.feedback = dropFeedback;
		}
		public void drop(DropTargetEvent event) {
			dropConsole.append(">>drop\n");
			printEvent(event);
			String[] strings = null;
			if (TextTransfer.getInstance().isSupportedType(event.currentDataType) ||
			    RTFTransfer.getInstance().isSupportedType(event.currentDataType) ||
			    HTMLTransfer.getInstance().isSupportedType(event.currentDataType)) {
			    strings = new String[] {(String)event.data};
			}
			if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
				strings = (String[])event.data;
			}
			if (strings == null || strings.length == 0) {
				dropConsole.append("!!Invalid data dropped");
				return;
			}
			
			if (strings.length == 1 && (dropControlType == TABLE || 
			                            dropControlType == TREE || 
			                            dropControlType == LIST)) {
				// convert string separated by "\n" into an array of strings 
				String string = strings[0];
				int count = 0;
				int offset = string.indexOf("\n", 0);
				while (offset > 0) {
					count++;
					offset = string.indexOf("\n", offset + 1);
				}
				if (count > 0) {
					strings = new String[count + 1];
					int start = 0;
					int end = string.indexOf("\n");
					int index = 0;
					while (start < end) {
						strings[index++] = string.substring(start, end);
						start = end + 1;
						end = string.indexOf("\n", start);
						if (end == -1) end = string.length();
					}
				}
			}
			switch(dropControlType) {
				case BUTTON_CHECK:
				case BUTTON_TOGGLE:
				case BUTTON_RADIO: {
					Button b = (Button)dropControl;
					b.setText(strings[0]);
					break;
				}
				case STYLED_TEXT: {
					StyledText text = (StyledText)dropControl;
					for(int i = 0; i < strings.length; i++) {
						text.insert(strings[i]);
					}
					break;
				}
				case TABLE: {
					Table table = (Table)dropControl;
					Point p = event.display.map(null, table, event.x, event.y);
					TableItem dropItem = table.getItem(p);
					int index = dropItem == null ? table.getItemCount() : table.indexOf(dropItem);
					for(int i = 0; i < strings.length; i++) {
						TableItem item = new TableItem(table, SWT.NONE, index);
						item.setText(0, strings[i]);
						item.setText(1, "dropped item");
					}
					TableColumn[] columns = table.getColumns();
					for (int i = 0; i < columns.length; i++) {
						columns[i].pack();
					}
					break;
				}
				case TEXT: {
					Text text = (Text)dropControl;
					for(int i = 0; i < strings.length; i++) {
						text.append(strings[i]+"\n");
					}
					break;
				}
				case TREE: {
					Tree tree = (Tree)dropControl;
					Point p = event.display.map(null, tree, event.x, event.y);
					TreeItem parentItem = tree.getItem(p);
					for(int i = 0; i < strings.length; i++) {
						TreeItem item = parentItem != null ? new TreeItem(parentItem, SWT.NONE) : new TreeItem(tree, SWT.NONE);
						item.setText(strings[i]);
					}
					break;
				}
				case CANVAS: {
					dropControl.setData("STRINGS", strings);
					dropControl.redraw();
					break;
				}
				case LABEL: {
					Label label = (Label)dropControl;
					label.setText(strings[0]);
					break;
				}
				case LIST: {
					List list = (List)dropControl;
					for(int i = 0; i < strings.length; i++) {
						list.add(strings[i]);
					}
					break;
				}
				default:
					throw new SWTError(SWT.ERROR_NOT_IMPLEMENTED);
			}
		}
		public void dropAccept(DropTargetEvent event) {
			dropConsole.append(">>dropAccept\n");
			printEvent(event);
		}
	});
}

private void createFeedbackTypes(Group parent) {
	parent.setLayout(new RowLayout(SWT.VERTICAL));
	Button b = new Button(parent, SWT.CHECK);
	b.setText("FEEDBACK_SELECT");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropFeedback |= DND.FEEDBACK_SELECT;			
			} else {
				dropFeedback &= ~DND.FEEDBACK_SELECT;
			}
		}
	});
	
	b = new Button(parent, SWT.CHECK);
	b.setText("FEEDBACK_SCROLL");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropFeedback |= DND.FEEDBACK_SCROLL;			
			} else {
				dropFeedback &= ~DND.FEEDBACK_SCROLL;
			}
		}
	});
	
	
	b = new Button(parent, SWT.CHECK);
	b.setText("FEEDBACK_INSERT_BEFORE");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropFeedback |= DND.FEEDBACK_INSERT_BEFORE;			
			} else {
				dropFeedback &= ~DND.FEEDBACK_INSERT_BEFORE;
			}
		}
	});
	
	b = new Button(parent, SWT.CHECK);
	b.setText("FEEDBACK_INSERT_AFTER");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropFeedback |= DND.FEEDBACK_INSERT_AFTER;
			} else {
				dropFeedback &= ~DND.FEEDBACK_INSERT_AFTER;
			}
		}
	});
	
	b = new Button(parent, SWT.CHECK);
	b.setText("FEEDBACK_EXPAND");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				dropFeedback |= DND.FEEDBACK_EXPAND;			
			} else {
				dropFeedback &= ~DND.FEEDBACK_EXPAND;
			}
		}
	});
}

private void createDropTypes(Composite parent) {
	parent.setLayout(new RowLayout(SWT.VERTICAL));
	Button textButton = new Button(parent, SWT.CHECK);
	textButton.setText("Text Transfer");
	textButton.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDropTransfer(TextTransfer.getInstance());			
			} else {
				removeDropTransfer(TextTransfer.getInstance());
			}
		}
	});
	
	Button b = new Button(parent, SWT.CHECK);
	b.setText("RTF Transfer");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDropTransfer(RTFTransfer.getInstance());			
			} else {
				removeDropTransfer(RTFTransfer.getInstance());
			}
		}
	});
	
	
	b = new Button(parent, SWT.CHECK);
	b.setText("HTML Transfer");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDropTransfer(HTMLTransfer.getInstance());			
			} else {
				removeDropTransfer(HTMLTransfer.getInstance());
			}
		}
	});
	
	b = new Button(parent, SWT.CHECK);
	b.setText("File Transfer");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			if (b.getSelection()) {
				addDropTransfer(FileTransfer.getInstance());			
			} else {
				removeDropTransfer(FileTransfer.getInstance());
			}
		}
	});
	
	// initialize state
	textButton.setSelection(true);
	addDropTransfer(TextTransfer.getInstance());
}

private void createDropWidget(Composite parent) {
	parent.setLayout(new FormLayout());
	Combo combo = new Combo(parent, SWT.READ_ONLY);
	combo.setItems(new String[] {"Toggle Button", "Radio Button", "Checkbox", "Canvas", "Label", "List", "Table", "Tree", "Text", "StyledText"});
	combo.select(LABEL);
	dropControlType = combo.getSelectionIndex();
	dropControl = createWidget(dropControlType, parent, "Drop Target");
	combo.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Object data = dropControl.getLayoutData();
			Composite parent = dropControl.getParent();
			dropControl.dispose();
			Combo c = (Combo)e.widget;
			dropControlType = c.getSelectionIndex(); 
			dropControl = createWidget(dropControlType, parent, "Drop Target");
			dropControl.setLayoutData(data);
			if (dropEnabled) createDropTarget();
			parent.layout();
		}
	});
	
	Button b = new Button(parent, SWT.CHECK);
	b.setText("DropTarget");
	b.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			Button b = (Button)e.widget;
			dropEnabled = b.getSelection();
			if (dropEnabled) {
				createDropTarget();
			} else {
				if (dropTarget != null){
					dropTarget.dispose();
				}
				dropTarget = null;
			}
		}
	});
	// initialize state
	b.setSelection(true);
	dropEnabled = true;
	
	FormData data = new FormData();
	data.top = new FormAttachment(0, 10);
	data.bottom = new FormAttachment(combo, -10);
	data.left = new FormAttachment(0, 10);
	data.right = new FormAttachment(100, -10);
	dropControl.setLayoutData(data);
	
	data = new FormData();
	data.bottom = new FormAttachment(100, -10);
	data.left = new FormAttachment(0, 10);
	combo.setLayoutData(data);
	
	data = new FormData();
	data.bottom = new FormAttachment(100, -10);
	data.left = new FormAttachment(combo, 10);
	b.setLayoutData(data);
}

private Control createWidget(int type, Composite parent, String prefix){
	switch (type) {
		case BUTTON_CHECK: {
			Button button = new Button(parent, SWT.CHECK);
			button.setText(prefix+" Check box");
			return button;
		}
		case BUTTON_TOGGLE: {
			Button button = new Button(parent, SWT.TOGGLE);
			button.setText(prefix+" Toggle button");
			return button;
		}
		case BUTTON_RADIO: {
			Button button = new Button(parent, SWT.RADIO);
			button.setText(prefix+" Radio button");
			return button;
		}
		case STYLED_TEXT: {
			StyledText text = new StyledText(parent, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
			text.setText(prefix+" Styled Text");
			return text;
		}
		case TABLE: {
			Table table = new Table(parent, SWT.BORDER | SWT.MULTI);
			table.setHeaderVisible(true);
			TableColumn column0 = new TableColumn(table, SWT.LEFT);
			column0.setText("Name");
			TableColumn column1 = new TableColumn(table, SWT.RIGHT);
			column1.setText("Value");
			TableColumn column2 = new TableColumn(table, SWT.CENTER);
			column2.setText("Description");
			for (int i = 0; i < 10; i++) {
				TableItem item = new TableItem(table, SWT.NONE);
				item.setText(0, prefix+" name "+i);
				item.setText(1, prefix+" value "+i);
				item.setText(2, prefix+" description "+i);
			}
			column0.pack();
			column1.pack();
			column2.pack();
			return table;
		}
		case TEXT: {
			Text text = new Text(parent, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
			text.setText(prefix+" Text");
			return text;
		}
		case TREE: {
			Tree tree = new Tree(parent, SWT.BORDER | SWT.MULTI);
			tree.setHeaderVisible(true);
			TreeColumn column0 = new TreeColumn(tree, SWT.LEFT);
			column0.setText("Name");
			TreeColumn column1 = new TreeColumn(tree, SWT.RIGHT);
			column1.setText("Value");
			TreeColumn column2 = new TreeColumn(tree, SWT.CENTER);
			column2.setText("Description");
			for (int i = 0; i < 3; i++) {
				TreeItem item = new TreeItem(tree, SWT.NONE);
				item.setText(0, prefix+" name "+i);
				item.setText(1, prefix+" value "+i);
				item.setText(2, prefix+" description "+i);
				for (int j = 0; j < 3; j++) {
					TreeItem subItem = new TreeItem(item, SWT.NONE);
					subItem.setText(0, prefix+" name "+i+" "+j);
					subItem.setText(1, prefix+" value "+i+" "+j);
					subItem.setText(2, prefix+" description "+i+" "+j);
					for (int k = 0; k < 3; k++) {
						TreeItem subsubItem = new TreeItem(subItem, SWT.NONE);
						subsubItem.setText(0, prefix+" name "+i+" "+j+" "+k);
						subsubItem.setText(1, prefix+" value "+i+" "+j+" "+k);
						subsubItem.setText(2, prefix+" description "+i+" "+j+" "+k);
					}
				}
			}
			column0.pack();
			column1.pack();
			column2.pack();
			return tree;
		}
		case CANVAS: {
			Canvas canvas = new Canvas(parent, SWT.BORDER);
			canvas.setData("STRINGS", new String[] {prefix+" Canvas widget"});
			canvas.addPaintListener(new PaintListener() {
				public void paintControl(PaintEvent e) {
					Canvas c = (Canvas)e.widget;
					Image image = (Image)c.getData("IMAGE");
					if (image != null) {
						e.gc.drawImage(image, 5, 5);
					} else {
						String[] strings = (String[])c.getData("STRINGS");
						if (strings != null) {
							FontMetrics metrics = e.gc.getFontMetrics();
							int height = metrics.getHeight();
							int y = 5;
							for(int i = 0; i < strings.length; i++) {
								e.gc.drawString(strings[i], 5, y);
								y += height + 5;
							}
						}
					}
				}
			});
			return canvas;
		}
		case LABEL: {
			Label label = new Label(parent, SWT.BORDER);
			label.setText(prefix+" Label");
			return label;
		}
		case LIST: {
			List list = new List(parent, SWT.BORDER);
			list.setItems(new String[] {prefix+" Item a", prefix+" Item b",  prefix+" Item c",  prefix+" Item d"});
			return list;
		}
		default:
			throw new SWTError(SWT.ERROR_NOT_IMPLEMENTED);
	}
}

public void open(Display display) {
	Shell shell = new Shell(display);
	shell.setText("Drag and Drop Example");
	shell.setLayout(new FillLayout());
	
	ScrolledComposite sc = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL);
	Composite parent = new Composite(sc, SWT.NONE);
	sc.setContent(parent);
	parent.setLayout(new FormLayout());
	
	Label dragLabel = new Label(parent, SWT.LEFT);
	dragLabel.setText("Drag Source:");
	
	Group dragWidgetGroup = new Group(parent, SWT.NONE);
	dragWidgetGroup.setText("Widget");
	createDragWidget(dragWidgetGroup);
	
	Composite cLeft = new Composite(parent, SWT.NONE);
	cLeft.setLayout(new GridLayout(2, false));
	
	Group dragOperationsGroup = new Group(cLeft, SWT.NONE);
	dragOperationsGroup.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false, 1, 1));
	dragOperationsGroup.setText("Allowed Operation(s):");
	createDragOperations(dragOperationsGroup);
	
	Group dragTypesGroup = new Group(cLeft, SWT.NONE);
	dragTypesGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
	dragTypesGroup.setText("Transfer Type(s):");
	createDragTypes(dragTypesGroup);
	
	dragConsole = new Text(cLeft, SWT.READ_ONLY | SWT.BORDER |SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
	dragConsole.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
	Menu menu = new Menu (shell, SWT.POP_UP);
	MenuItem item = new MenuItem (menu, SWT.PUSH);
	item.setText ("Clear");
	item.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			dragConsole.setText("");
		}
	});
	item = new MenuItem (menu, SWT.CHECK);
	item.setText ("Show Event detail");
	item.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			MenuItem item = (MenuItem)e.widget;
			dragEventDetail = item.getSelection();
		}
	});
	dragConsole.setMenu(menu);
	
	Label dropLabel = new Label(parent, SWT.LEFT);
	dropLabel.setText("Drop Target:");
	
	Group dropWidgetGroup = new Group(parent, SWT.NONE);
	dropWidgetGroup.setText("Widget");
	createDropWidget(dropWidgetGroup);
	
	Composite cRight = new Composite(parent, SWT.NONE);
	cRight.setLayout(new GridLayout(2, false));
	
	Group dropOperationsGroup = new Group(cRight, SWT.NONE);
	dropOperationsGroup.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false, 1, 2));
	dropOperationsGroup.setText("Allowed Operation(s):");
	createDropOperations(dropOperationsGroup);
	
	Group dropTypesGroup = new Group(cRight, SWT.NONE);
	dropTypesGroup.setText("Transfer Type(s):");
	createDropTypes(dropTypesGroup);
	
	Group feedbackTypesGroup = new Group(cRight, SWT.NONE);
	feedbackTypesGroup.setText("Feedback Type(s):");
	createFeedbackTypes(feedbackTypesGroup);
	
	dropConsole = new Text(cRight, SWT.READ_ONLY | SWT.BORDER |SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI);
	dropConsole.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
	menu = new Menu (shell, SWT.POP_UP);
	item = new MenuItem (menu, SWT.PUSH);
	item.setText ("Clear");
	item.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			dropConsole.setText("");
		}
	});
	item = new MenuItem (menu, SWT.CHECK);
	item.setText ("Show Event detail");
	item.addSelectionListener(new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			MenuItem item = (MenuItem)e.widget;
			dropEventDetail = item.getSelection();
		}
	});
	dropConsole.setMenu(menu);
	
	if (dragEnabled) createDragSource();
	if (dropEnabled) createDropTarget();
	
	int height = 200;
	FormData data = new FormData();
	data.top = new FormAttachment(0, 10);
	data.left = new FormAttachment(0, 10);
	dragLabel.setLayoutData(data);
	
	data = new FormData();
	data.top = new FormAttachment(dragLabel, 10);
	data.left = new FormAttachment(0, 10);
	data.right = new FormAttachment(50, -10);
	data.height = height;
	dragWidgetGroup.setLayoutData(data);
	
	data = new FormData();
	data.top = new FormAttachment(dragWidgetGroup, 10);
	data.left = new FormAttachment(0, 10);
	data.right = new FormAttachment(50, -10);
	data.bottom = new FormAttachment(100, -10);
	cLeft.setLayoutData(data);

	data = new FormData();
	data.top = new FormAttachment(0, 10);
	data.left = new FormAttachment(cLeft, 10);
	dropLabel.setLayoutData(data);
	
	data = new FormData();
	data.top = new FormAttachment(dropLabel, 10);
	data.left = new FormAttachment(cLeft, 10);
	data.right = new FormAttachment(100, -10);
	data.height = height;
	dropWidgetGroup.setLayoutData(data);
	
	data = new FormData();
	data.top = new FormAttachment(dropWidgetGroup, 10);
	data.left = new FormAttachment(cLeft, 10);
	data.right = new FormAttachment(100, -10);
	data.bottom = new FormAttachment(100, -10);
	cRight.setLayoutData(data);
		
	sc.setMinSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
	sc.setExpandHorizontal(true);
	sc.setExpandVertical(true);
	
	Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
	Rectangle monitorArea = shell.getMonitor().getClientArea();
	shell.setSize(Math.min(size.x, monitorArea.width - 20), Math.min(size.y, monitorArea.height - 20));
	shell.open();
		
	while (!shell.isDisposed()) {
		if (!display.readAndDispatch())
			display.sleep();
	}	
}

private void printEvent(DragSourceEvent e) {
	if (!dragEventDetail) return;
	StringBuffer sb = new StringBuffer();
	sb.append("widget: "); sb.append(e.widget);
	sb.append(", time: "); sb.append(e.time);
	sb.append(", operation: "); sb.append(e.detail);
	sb.append(", type: "); sb.append(e.dataType != null ? e.dataType.type : 0);
	sb.append(", doit: "); sb.append(e.doit);
	sb.append(", data: "); sb.append(e.data);
	sb.append("\n");
	dragConsole.append(sb.toString());
}

private void printEvent(DropTargetEvent e) {
	if (!dropEventDetail) return;
	StringBuffer sb = new StringBuffer();
	sb.append("widget; "); sb.append(e.widget);
	sb.append(", time: "); sb.append(e.time);
	sb.append(", x: "); sb.append(e.x);
	sb.append(", y: "); sb.append(e.y);
	sb.append(", item: "); sb.append(e.item);
	sb.append(", operations: "); sb.append(e.operations);
	sb.append(", operation: "); sb.append(e.detail);
	sb.append(", feedback: "); sb.append(e.feedback);
	if (e.dataTypes != null) {
		for (int i = 0; i < e.dataTypes.length; i++) {
			sb.append(", dataType "); sb.append(i); sb.append(": "); sb.append(e.dataTypes[i].type);
		}
	} else {
		sb.append(", dataTypes: none");
	}
	sb.append(", currentDataType: "); sb.append(e.currentDataType);
	sb.append(", data: "); sb.append(e.data);
	sb.append("\n");
	dropConsole.append(sb.toString());
}

private void removeDragTransfer(Transfer transfer){
	if (dragTypes.length == 1) {
		dragTypes = new Transfer[0];
	} else {
		int index = -1;
		for(int i = 0; i < dragTypes.length; i++) {
			if (dragTypes[i] == transfer) {
				index = i;
				break;
			}
		}
		if (index == -1) return;
		Transfer[] newTypes = new Transfer[dragTypes.length - 1];
		System.arraycopy(dragTypes, 0, newTypes, 0, index);
		System.arraycopy(dragTypes, index + 1, newTypes, index, dragTypes.length - index - 1);
		dragTypes = newTypes;
	}
	if (dragSource != null) {
		dragSource.setTransfer(dragTypes);
	}
}

private void removeDropTransfer(Transfer transfer){
	if (dropTypes.length == 1) {
		dropTypes = new Transfer[0];
	} else {
		int index = -1;
		for(int i = 0; i < dropTypes.length; i++) {
			if (dropTypes[i] == transfer) {
				index = i;
				break;
			}
		}
		if (index == -1) return;
		Transfer[] newTypes = new Transfer[dropTypes.length - 1];
		System.arraycopy(dropTypes, 0, newTypes, 0, index);
		System.arraycopy(dropTypes, index + 1, newTypes, index, dropTypes.length - index - 1);
		dropTypes = newTypes;
	}
	if (dropTarget != null) {
		dropTarget.setTransfer(dropTypes);
	}
}
}
