工作台窗口的Editor区域默认是显示的,而且它支持拖拽操作。在Eclipse里面,把一个文件拖到Editor区域,就会自动打开该文件的Editor。该特性是在IWorkbenchWindowConfigurer 中设置。
工作台窗口的Editor区域默认是显示的,而且它支持拖拽操作。在Eclipse里面,把一个文件拖到Editor区域,就会自动打开该文件的Editor。该特性是在
IWorkbenchWindowConfigurer 中设置。
在Password Gate中,当拖动Password Gate View中的一个Group 或者 Service到Editor区域,会在Editor显示该项的属性。
要实现此特性,有四部分是必须的。
1 实现必要的Transfer类型,而且定义Editor要支持哪些类型。在Password Gate中,Transfer是LocalSelectionTransfer。Transfer用来进行数据的序列化,它可以支持在同一个程序,或不同程序间拖拽。
2 因为在拖拽传递的过程中Editor Input 要实现序列化,所以要实现IPersistableElement接口。
3 加入一个释放适配器,当一个元素被扔到Editor区域,它可以知道如何进行操作,其实就是打开该元素的Editor。
4 使Password View能够进行拖操作,它要提供供拖的元素。
下面进行代码实现。
在RCP的WorkbenchWindowAdvisor. preWindowOpen中定义要求Editor Area支持的拖入对象的类型,以及打开相应Editor的事件。
ApplicationWorkbenchWindowAdvisor.preWindowOpen()
01 public void preWindowOpen() { 02 ...... 03 configurer.addEditorAreaTransfer(LocalSelectionTransfer.getInstance()); 04 configurer.configureEditorAreaDropListener(new EditorAreaDropAdapter( 05 configurer.getWindow())); 06 } |
Row 03定义了Editor Area支持的Transfer为LocalSelectionTransfer, LocalSelectionTransfer为自己实现的传输介质类。Row 04定义了对拖入Editor Area的对象的处理方法。EditorAreaDropAdapter实现了DropTargetListener接口,用来监听Editor Area中的Drop事件,它会打开拖入Editor Area的对象所对应的Editor,如果同时拖入多个对象,它会打开每个对象对应的Editor.
EditorAreaDropAdapter.java |
01 public class EditorAreaDropAdapter extends DropTargetAdapter { 02 private IWorkbenchWindow window; 03 04 public EditorAreaDropAdapter(IWorkbenchWindow window) { 05 this.window = window; 06 } 07 08 public void dragEnter(DropTargetEvent event) { 09 // always indicate a copy 10 event.detail = DND.DROP_COPY; 11 } 12 13 public void dragOperationChanged(DropTargetEvent event) { 14 // always indicate a copy 15 event.detail = DND.DROP_COPY; 16 } 17 18 public void drop(final DropTargetEvent event) { 19 Display d = window.getShell().getDisplay(); 20 final IWorkbenchPage page = window.getActivePage(); 21 if (page != null) { 22 d.asyncExec(new Runnable() { 23 public void run() { 24 asyncDrop(event, page); 25 } 26 }); 27 } 28 } 29 30 private void asyncDrop(DropTargetEvent event, IWorkbenchPage page) { 31 if (LocalSelectionTransfer.getInstance().isSupportedType( 32 event.currentDataType)) { 33 StructuredSelection selection = (StructuredSelection) event.data; 34 for (Iterator iter = selection.iterator(); iter.hasNext();) { 35 Object o = iter.next(); 36 if (o instanceof Record) { 37 IEditorInput input = new RecordEditorInput((Record) o); 38 try { 39 page.openEditor(input, RecordEditor.ID); 40 } catch (Exception e) { 41 PwdgatePlugin.log("open ediotr RecordEditor", e); 42 } 43 } else if (o instanceof Group) { 44 IEditorInput input = new GroupEditorInput((Group) o); 45 try { 46 page.openEditor(input, GroupEditor.ID); 47 } catch (PartInitException e) { 48 PwdgatePlugin.log("open ediotr GroupEditor", e); 49 } 50 } 51 } 52 } 53 } 54 } |
Row 18,用来处理Drop事件,Row 30的asyncDrop()方法用来打来相应对象的Editor.
现在Editor Area已经可以接收拖入对象了。下一步要使一个View支持拖出对象的功能。下面的例子是在Pass Gate View中的createPartControl()方法中为一个TreeViewer添加拖出功能。
PassGateView.java |
01 private void initDragAndDrop() { 02 Transfer[] transfer = new Transfer[] { LocalSelectionTransfer 03 .getInstance() }; 04 LocalSelectionDragAdapter adapter = new LocalSelectionDragAdapter( 05 viewer); 06 viewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, transfer, adapter); 07 08 LocalSelectionDropAdapter dropAdapter = new LocalSelectionDropAdapter( 09 viewer); 10 viewer.addDropSupport(DND.DROP_MOVE | DND.DROP_COPY, transfer, 11 dropAdapter); 12 } |
Row 06 为TreeViewer添加了监听拖动的事件,当在TreeViewer中有拖动时,LocalSelectionDragAdapter把拖动的对象放入LocalSelectionTransfer中,通过其传到 Editor Area中。
LocalSelectionDragAdapter.java |
01 public class LocalSelectionDragAdapter extends DragSourceAdapter { 02 03 ISelectionProvider selectionProvider; 04 05 public LocalSelectionDragAdapter(ISelectionProvider provider) { 06 selectionProvider = provider; 07 } 08 09 public void dragFinished(DragSourceEvent event) { 10 // TODO Auto-generated method stub 11 super.dragFinished(event); 12 System.out 13 .println("DragSourceListener.dragFinished(DragSourceEvent event)"); 14 } 15 16 public void dragSetData(DragSourceEvent event) { 17 System.out 18 .println("DragSourceListener.dragSetData(DragSourceEvent event)"); 19 DragSource dragSource = (DragSource) event.widget; 20 Control control = dragSource.getControl(); 21 if (control != control.getDisplay().getFocusControl()) { 22 event.doit = false; 23 return; 24 } 25 26 IStructuredSelection selection = (IStructuredSelection) selectionProvider 27 .getSelection(); 28 29 if (selection.isEmpty()) { 30 event.doit = false; 31 return; 32 } 33 LocalSelectionTransfer.getInstance().setSelection(selection); 34 event.doit = true; 35 } 36 37 public void dragStart(DragSourceEvent event) { 38 System.out 39 .println("DragSourceListener.dragStart(DragSourceEvent event)"); 40 } 41 } |
Row 33 ,将拖动的对象放入LocalSelectionTransfer中。Row 44 设置拖动有效,设为false的话,拖动无效。下面是LocalSelectionTransfer的实现。很容易理解。
LocalSelectionTransfer.java |
001 public class LocalSelectionTransfer extends ByteArrayTransfer { 002 003 private static final String TYPE_NAME = "local-selection-transfer-format" + (new Long(System.currentTimeMillis())).toString(); //$NON-NLS-1$; 004 005 private static final int TYPEID = registerType(TYPE_NAME); 006 007 private static final LocalSelectionTransfer INSTANCE = new LocalSelectionTransfer(); 008 009 private ISelection selection; 010 011 private long selectionSetTime; 012 013 /** 014 * Only the singleton instance of this class may be used. 015 */ 016 private LocalSelectionTransfer() { 017 } 018 019 /** 020 * Returns the singleton. 021 * 022 * @return LocalSelectionTransfer 023 */ 024 public static LocalSelectionTransfer getInstance() { 025 return INSTANCE; 026 } 027 028 /** 029 * Returns the local transfer data. 030 * 031 * @return the local transfer data 032 */ 033 public ISelection getSelection() { 034 return selection; 035 } 036 037 /** 038 * Tests whether native drop data matches this transfer type. 039 * 040 * @param result 041 * result of converting the native drop data to Java 042 * @return true if the native drop data does not match this transfer type. 043 * false otherwise. 044 */ 045 private boolean isInvalidNativeType(Object result) { 046 return !(result instanceof byte[]) 047 || !TYPE_NAME.equals(new String((byte[]) result)); 048 } 049 050 /** 051 * Returns the type id used to identify this transfer. 052 * 053 * @return the type id used to identify this transfer. 054 */ 055 protected int[] getTypeIds() { 056 return new int[] { TYPEID }; 057 } 058 059 /** 060 * Returns the type name used to identify this transfer. 061 * 062 * @return the type name used to identify this transfer. 063 */ 064 protected String[] getTypeNames() { 065 return new String[] { TYPE_NAME }; 066 } 067 068 /** 069 * Overrides org.eclipse.swt.dnd.ByteArrayTransfer#javaToNative(Object, 070 * TransferData). Only encode the transfer type name since the selection is 071 * read and written in the same process. 072 * 073 * @see org.eclipse.swt.dnd.ByteArrayTransfer#javaToNative(java.lang.Object, 074 * org.eclipse.swt.dnd.TransferData) 075 */ 076 public void javaToNative(Object object, TransferData transferData) { 077 byte[] check = TYPE_NAME.getBytes(); 078 super.javaToNative(check, transferData); 079 } 080 081 /** 082 * Overrides 083 * org.eclipse.swt.dnd.ByteArrayTransfer#nativeToJava(TransferData). Test if 084 * the native drop data matches this transfer type. 085 * 086 * @see org.eclipse.swt.dnd.ByteArrayTransfer#nativeToJava(TransferData) 087 */ 088 public Object nativeToJava(TransferData transferData) { 089 Object result = super.nativeToJava(transferData); 090 if (isInvalidNativeType(result)) { 091 PwdgatePlugin.log("invalid nattive type", new Exception( 092 "invalid nattive type")); 093 } 094 return selection; 095 } 096 097 /** 098 * Sets the transfer data for local use. 099 * 100 * @param s 101 * the transfer data 102 */ 103 public void setSelection(ISelection s) { 104 selection = s; 105 } 106 107 /** 108 * Returns the time when the selection operation this transfer is associated 109 * with was started. 110 * 111 * @return the time when the selection operation has started 112 * 113 * @see org.eclipse.swt.events.TypedEvent#time 114 */ 115 public long getSelectionSetTime() { 116 return selectionSetTime; 117 } 118 119 /** 120 * Sets the time when the selection operation this transfer is associated 121 * with was started. If assigning this from an SWT event, be sure to use 122 * <code>setSelectionTime(event.time & 0xFFFF)</code> 123 * 124 * @param time 125 * the time when the selection operation was started 126 * 127 * @see org.eclipse.swt.events.TypedEvent#time 128 */ 129 public void setSelectionSetTime(long time) { 130 selectionSetTime = time; 131 } 132 } |
其实不光是拖到Area Editor,以上例子稍加改造,也可以实现拖到别的控件中,任何Control都可以添加托拽功能,例如可以从一个表格拖到另一个表格中,或拖到一个面板中。托拽功能让软件的可用性又提高了一个档次。