本文属CNF系列汇总中的第三篇,主要介绍自定义导航中如何实现文件拖拽功能。
分析
CNF 提供了标准的拖拽操作支持——Drag and Drop Support,Drag and Drop Support 指的就是节点的拖放操作。
CNF 实现拖拽操作需要实现两个扩展点
-
Drag 扩展点为
dragAssistant
这个扩展点提供“拖”操作的支持,位于 org.eclipse.ui.navigator.viewer 扩展点下。
dragAssistant
有class和viewerId两个属性,class属性指定了drag操作的实现类,该类必须继承org.eclipse.ui.navigator.CommonDragAdapterAssistant
。viewerId 用于指定该拖动实现作用于哪个导航视图(org.eclipse.ui.navigator.viewer)。 -
Drop 扩展点
dropAssistant
,这个扩展点处理“放”的功能,位于org.eclipse.ui.navigator.navigatorContent
下。设计在 navigatorContent 里面声明,大概是因为 Drop 操作不能在不同的 navigatorContent 之间共享的缘故。
dropAssistant
也有两个属性,分别是id和class,分别为“放”操作的实现类ID和实现类,放的实现类必须继承org.eclipse.ui.navigator.CommonDropAdapterAssistant
其中org.eclipse.ui.navigator.CommonDragAdapterAssistant
和org.eclipse.ui.navigator.CommonDropAdapterAssistant
由CNF框架提供。
实现
引用Eclipse Explorer Viewer 的实现
Explorer Viewer 对Drag和Drop的实现类分别是org.eclipse.ui.navigator.resources.ResourceDragAdapterAssistant
和org.eclipse.ui.navigator.resources.ResourceDropAdapterAssistant
。以下我们引用这两个实现,使得自定义导航拥有与Eclipse 导航同样的拖拽功能。
- Drag 的 plugin.xml 配置
<extension
point="org.eclipse.ui.navigator.viewer">
<viewer viewerId="com.xzbd.views.MainNavigator">
<!-- …… 篇幅问题省去其他代码 -->
<dragAssistant
class="com.xzbd.navigator.dnd.DragAdapterAssistant"
viewerId="com.xzbd.views.MainNavigator">
</dragAssistant>
</extension>
- Drop 的 plugin.xml 配置
<extension
point="org.eclipse.ui.navigator.navigatorContent">
<navigatorContent
activeByDefault="true"
id="com.xzbd.epx.MainNavigatorContent"
name="mainNavigatorContent"
labelProvider="com.xzbd.navigator.provider.MainLabelProvider"
contentProvider="com.xzbd.navigator.provider.MainContentProvider"
priority="normal">
<!-- 省略triggerPoints和possibleChildren -->
<!-- 新建文件向导 省略-->
<!-- 新建文件夹向导 省略-->
<dropAssistant
class="com.xzbd.navigator.dnd.DropAdapterAssistant"
id="com.xzbd.navigator.dnd.DropAdapterAssistant">
<possibleDropTargets></possibleDropTargets>
</dropAssistant>
</navigatorContent>
<!-- 自定义导航 省略-->
<!-- 编辑按钮组 省略-->
<!-- 新建按钮组 省略 -->
</extension>
注意dropAssistant
标签的ID属性是自定义的。
拖拽和放的实现类方法直接继承Eclipse实现类即可。
- 拖拽的实现类
package com.xzbd.navigator.dnd;
import org.eclipse.ui.navigator.resources.ResourceDragAdapterAssistant;
public class DragAdapterAssistant extends ResourceDragAdapterAssistant{
public static final String ID = "com.xzbd.navigator.dnd.DragAdapterAssistant";
}
- 放的实现类
package com.xzbd.navigator.dnd;
import org.eclipse.ui.navigator.resources.ResourceDropAdapterAssistant;
public class DropAdapterAssistant extends ResourceDropAdapterAssistant {
public static final String ID = "com.xzbd.navigator.dnd.DropAdapterAssistant";
}
此时启动项目,testProject01
和testProject02
中新建文件夹及文件,尝试拖动,会发现已经可以实现拖动了。
实现自己的规则
以上实现,尝试拖动发现,文件可以在不同的项目之间拖动,现假设需求为:不允许文件在项目间拖动
此需求只需要在com.xzbd.navigator.dnd.DropAdapterAssistant
重写方法即可。,重写后的实现如下
package com.xzbd.navigator.dnd;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.ui.navigator.CommonDropAdapter;
import org.eclipse.ui.navigator.resources.ResourceDropAdapterAssistant;
import com.xzbd.utils.AppPrinter;
import com.xzbd.utils.WorkbenchUtil;
public class DropAdapterAssistant extends ResourceDropAdapterAssistant {
public static final String ID = "com.xzbd.navigator.dnd.DropAdapterAssistant";
@Override
public IStatus handleDrop(CommonDropAdapter aDropAdapter, DropTargetEvent aDropTargetEvent, Object destTarget) {
// 获取当前拖动的数据
Object data = aDropTargetEvent.data;
if(Objects.isNull(data)) {
return Status.CANCEL_STATUS;
}
// 如果不是类型不是 TreeSelection ,因为导航视图的资源实现自 TreeSelection
if(!(data instanceof TreeSelection)) {
return Status.CANCEL_STATUS;
}
TreeSelection treeSelection = (TreeSelection)data;
// 所有拖动资源的项目名
Set<String> projectNames = new HashSet<>();
Iterator<?> iterator = treeSelection.iterator();
while (iterator.hasNext()) {
String pName = WorkbenchUtil.getProjectName(iterator.next());
if(pName != null && !pName.isBlank()) {
projectNames.add(pName);
}
}
// 获取目标资源所在的项目名
String destProjectName = WorkbenchUtil.getProjectName(destTarget);
// 如果有一个被拖文件与目标不是在同一个项目,则取消整个拖拽操作
for(String pName : projectNames) {
if(!pName.equals(destProjectName)) {
AppPrinter.println("资源与目标不是同一个项目,取消拖拽" );
return Status.CANCEL_STATUS;
}
}
return super.handleDrop(aDropAdapter, aDropTargetEvent, destTarget);
}
}
如此就实现了资源拖拽的控制需求:不允许文件在项目间拖动。当触发资源在项目间拖动时,软件控制台将打印 资源与目标不是同一个项目,取消拖拽
效果
拖放效果无法截图展示,请前往项目地址拉项目,自己尝试。
系列文章
CNF系列汇总
Common Navigator Framework 实践(一)自定义导航
Common Navigator Framework 实践(二)菜单扩展
Common Navigator Framework 实践(三)文件拖拽控制
Common Navigator Framework 实践(四)文件过滤
Common Navigator Framework 实践(五)菜单及工具条定制