| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author cdr |
| */ |
| package com.intellij.ide.projectView.impl; |
| |
| import com.intellij.ide.DataManager; |
| import com.intellij.ide.PsiCopyPasteManager; |
| import com.intellij.ide.SelectInTarget; |
| import com.intellij.ide.dnd.*; |
| import com.intellij.ide.dnd.aware.DnDAwareTree; |
| import com.intellij.ide.projectView.BaseProjectTreeBuilder; |
| import com.intellij.ide.projectView.ProjectView; |
| import com.intellij.ide.projectView.impl.nodes.AbstractModuleNode; |
| import com.intellij.ide.projectView.impl.nodes.AbstractProjectNode; |
| import com.intellij.ide.projectView.impl.nodes.ModuleGroupNode; |
| import com.intellij.ide.util.treeView.*; |
| import com.intellij.injected.editor.VirtualFileWindow; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.actionSystem.CommonDataKeys; |
| import com.intellij.openapi.actionSystem.DataContext; |
| import com.intellij.openapi.actionSystem.DataProvider; |
| import com.intellij.openapi.actionSystem.DefaultActionGroup; |
| import com.intellij.openapi.actionSystem.PlatformDataKeys; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.extensions.ExtensionPointName; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.module.ModuleUtilCore; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ModuleRootManager; |
| import com.intellij.openapi.util.*; |
| import com.intellij.openapi.util.registry.Registry; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.openapi.wm.ToolWindowId; |
| import com.intellij.openapi.wm.ToolWindowManager; |
| import com.intellij.pom.Navigatable; |
| import com.intellij.problems.WolfTheProblemSolver; |
| import com.intellij.psi.*; |
| import com.intellij.psi.util.PsiUtilCore; |
| import com.intellij.refactoring.move.MoveHandler; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.ReflectionCache; |
| import com.intellij.util.containers.HashMap; |
| import com.intellij.util.ui.UIUtil; |
| import com.intellij.util.ui.tree.TreeUtil; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| import javax.swing.tree.TreeNode; |
| import javax.swing.tree.TreePath; |
| import java.awt.*; |
| import java.awt.datatransfer.Transferable; |
| import java.awt.dnd.DnDConstants; |
| import java.awt.image.BufferedImage; |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| |
| public abstract class AbstractProjectViewPane implements DataProvider, Disposable, BusyObject { |
| public static ExtensionPointName<AbstractProjectViewPane> EP_NAME = ExtensionPointName.create("com.intellij.projectViewPane"); |
| |
| @NotNull |
| protected final Project myProject; |
| private Runnable myTreeChangeListener; |
| protected DnDAwareTree myTree; |
| protected AbstractTreeStructure myTreeStructure; |
| private AbstractTreeBuilder myTreeBuilder; |
| // subId->Tree state; key may be null |
| private final Map<String,TreeState> myReadTreeState = new HashMap<String, TreeState>(); |
| private String mySubId; |
| @NonNls private static final String ELEMENT_SUBPANE = "subPane"; |
| @NonNls private static final String ATTRIBUTE_SUBID = "subId"; |
| |
| private DnDTarget myDropTarget; |
| private DnDSource myDragSource; |
| private DnDManager myDndManager; |
| |
| private void queueUpdateByProblem() { |
| if (Registry.is("projectView.showHierarchyErrors")) { |
| if (myTreeBuilder != null) { |
| myTreeBuilder.queueUpdate(); |
| } |
| } |
| } |
| |
| protected AbstractProjectViewPane(@NotNull Project project) { |
| myProject = project; |
| WolfTheProblemSolver.ProblemListener problemListener = new WolfTheProblemSolver.ProblemListener() { |
| @Override |
| public void problemsAppeared(@NotNull VirtualFile file) { |
| queueUpdateByProblem(); |
| } |
| |
| @Override |
| public void problemsChanged(@NotNull VirtualFile file) { |
| queueUpdateByProblem(); |
| } |
| |
| @Override |
| public void problemsDisappeared(@NotNull VirtualFile file) { |
| queueUpdateByProblem(); |
| } |
| }; |
| WolfTheProblemSolver.getInstance(project).addProblemListener(problemListener, this); |
| } |
| |
| protected final void fireTreeChangeListener() { |
| if (myTreeChangeListener != null) myTreeChangeListener.run(); |
| } |
| |
| public final void setTreeChangeListener(@NotNull Runnable listener) { |
| myTreeChangeListener = listener; |
| } |
| |
| public final void removeTreeChangeListener() { |
| myTreeChangeListener = null; |
| } |
| |
| public abstract String getTitle(); |
| public abstract Icon getIcon(); |
| @NotNull public abstract String getId(); |
| @Nullable public final String getSubId(){ |
| return mySubId; |
| } |
| |
| public final void setSubId(@Nullable String subId) { |
| if (Comparing.strEqual(mySubId, subId)) return; |
| saveExpandedPaths(); |
| mySubId = subId; |
| } |
| |
| public boolean isInitiallyVisible() { |
| return true; |
| } |
| |
| /** |
| * @return all supported sub views IDs. |
| * should return empty array if there is no subViews as in Project/Packages view. |
| */ |
| @NotNull public String[] getSubIds(){ |
| return ArrayUtil.EMPTY_STRING_ARRAY; |
| } |
| |
| @NotNull public String getPresentableSubIdName(@NotNull final String subId) { |
| throw new IllegalStateException("should not call"); |
| } |
| public abstract JComponent createComponent(); |
| public JComponent getComponentToFocus() { |
| return myTree; |
| } |
| public void expand(@Nullable final Object[] path, final boolean requestFocus){ |
| if (getTreeBuilder() == null || path == null) return; |
| getTreeBuilder().buildNodeForPath(path); |
| |
| DefaultMutableTreeNode node = getTreeBuilder().getNodeForPath(path); |
| if (node == null) { |
| return; |
| } |
| TreePath treePath = new TreePath(node.getPath()); |
| myTree.expandPath(treePath); |
| if (requestFocus) { |
| myTree.requestFocus(); |
| } |
| TreeUtil.selectPath(myTree, treePath); |
| } |
| |
| @Override |
| public void dispose() { |
| if (myDndManager != null) { |
| if (myDropTarget != null) { |
| myDndManager.unregisterTarget(myDropTarget, myTree); |
| myDropTarget = null; |
| } |
| if (myDragSource != null) { |
| myDndManager.unregisterSource(myDragSource, myTree); |
| myDragSource = null; |
| } |
| myDndManager = null; |
| } |
| setTreeBuilder(null); |
| myTree = null; |
| myTreeStructure = null; |
| } |
| |
| public abstract ActionCallback updateFromRoot(boolean restoreExpandedPaths); |
| |
| public abstract void select(Object element, VirtualFile file, boolean requestFocus); |
| public void selectModule(final Module module, final boolean requestFocus) { |
| doSelectModuleOrGroup(module, requestFocus); |
| } |
| |
| private void doSelectModuleOrGroup(final Object toSelect, final boolean requestFocus) { |
| ToolWindowManager windowManager=ToolWindowManager.getInstance(myProject); |
| final Runnable runnable = new Runnable() { |
| @Override |
| public void run() { |
| ProjectView projectView = ProjectView.getInstance(myProject); |
| if (requestFocus) { |
| projectView.changeView(getId(), getSubId()); |
| } |
| ((BaseProjectTreeBuilder)getTreeBuilder()).selectInWidth(toSelect, requestFocus, new Condition<AbstractTreeNode>(){ |
| @Override |
| public boolean value(final AbstractTreeNode node) { |
| return node instanceof AbstractModuleNode || node instanceof ModuleGroupNode || node instanceof AbstractProjectNode; |
| } |
| }); |
| } |
| }; |
| if (requestFocus) { |
| windowManager.getToolWindow(ToolWindowId.PROJECT_VIEW).activate(runnable); |
| } |
| else { |
| runnable.run(); |
| } |
| } |
| |
| public void selectModuleGroup(ModuleGroup moduleGroup, boolean requestFocus) { |
| doSelectModuleOrGroup(moduleGroup, requestFocus); |
| } |
| |
| public TreePath[] getSelectionPaths() { |
| return myTree == null ? null : myTree.getSelectionPaths(); |
| } |
| |
| public void addToolbarActions(DefaultActionGroup actionGroup) { |
| } |
| |
| @NotNull |
| protected <T extends NodeDescriptor> List<T> getSelectedNodes(final Class<T> nodeClass){ |
| TreePath[] paths = getSelectionPaths(); |
| if (paths == null) return Collections.emptyList(); |
| final ArrayList<T> result = new ArrayList<T>(); |
| for (TreePath path : paths) { |
| Object lastPathComponent = path.getLastPathComponent(); |
| if (lastPathComponent instanceof DefaultMutableTreeNode) { |
| DefaultMutableTreeNode node = (DefaultMutableTreeNode)lastPathComponent; |
| Object userObject = node.getUserObject(); |
| if (userObject != null && ReflectionCache.isAssignable(nodeClass, userObject.getClass())) { |
| result.add((T)userObject); |
| } |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public Object getData(String dataId) { |
| if (CommonDataKeys.NAVIGATABLE_ARRAY.is(dataId)) { |
| TreePath[] paths = getSelectionPaths(); |
| if (paths == null) return null; |
| final ArrayList<Navigatable> navigatables = new ArrayList<Navigatable>(); |
| for (TreePath path : paths) { |
| Object lastPathComponent = path.getLastPathComponent(); |
| if (lastPathComponent instanceof DefaultMutableTreeNode) { |
| DefaultMutableTreeNode node = (DefaultMutableTreeNode)lastPathComponent; |
| Object userObject = node.getUserObject(); |
| if (userObject instanceof Navigatable) { |
| navigatables.add((Navigatable)userObject); |
| } |
| else if (node instanceof Navigatable) { |
| navigatables.add((Navigatable)node); |
| } |
| } |
| } |
| if (navigatables.isEmpty()) { |
| return null; |
| } |
| else { |
| return navigatables.toArray(new Navigatable[navigatables.size()]); |
| } |
| } |
| if (myTreeStructure instanceof AbstractTreeStructureBase) { |
| return ((AbstractTreeStructureBase) myTreeStructure).getDataFromProviders(getSelectedNodes(AbstractTreeNode.class), dataId); |
| } |
| return null; |
| } |
| |
| // used for sorting tabs in the tabbed pane |
| public abstract int getWeight(); |
| |
| public abstract SelectInTarget createSelectInTarget(); |
| |
| public final TreePath getSelectedPath() { |
| final TreePath[] paths = getSelectionPaths(); |
| if (paths != null && paths.length == 1) return paths[0]; |
| return null; |
| } |
| |
| public final NodeDescriptor getSelectedDescriptor() { |
| final DefaultMutableTreeNode node = getSelectedNode(); |
| if (node == null) return null; |
| Object userObject = node.getUserObject(); |
| if (userObject instanceof NodeDescriptor) { |
| return (NodeDescriptor)userObject; |
| } |
| return null; |
| } |
| |
| public final DefaultMutableTreeNode getSelectedNode() { |
| TreePath path = getSelectedPath(); |
| if (path == null) { |
| return null; |
| } |
| Object lastPathComponent = path.getLastPathComponent(); |
| if (!(lastPathComponent instanceof DefaultMutableTreeNode)) { |
| return null; |
| } |
| return (DefaultMutableTreeNode)lastPathComponent; |
| } |
| |
| public final Object getSelectedElement() { |
| final Object[] elements = getSelectedElements(); |
| return elements.length == 1 ? elements[0] : null; |
| } |
| |
| @NotNull |
| public final PsiElement[] getSelectedPSIElements() { |
| List<PsiElement> psiElements = new ArrayList<PsiElement>(); |
| for (Object element : getSelectedElements()) { |
| final PsiElement psiElement = getPSIElement(element); |
| if (psiElement != null) { |
| psiElements.add(psiElement); |
| } |
| } |
| return PsiUtilCore.toPsiElementArray(psiElements); |
| } |
| |
| @Nullable |
| protected PsiElement getPSIElement(@Nullable final Object element) { |
| if (element instanceof PsiElement) { |
| PsiElement psiElement = (PsiElement)element; |
| if (psiElement.isValid()) { |
| return psiElement; |
| } |
| } |
| return null; |
| } |
| |
| @Nullable |
| protected Module getNodeModule(@Nullable final Object element) { |
| if (element instanceof PsiElement) { |
| PsiElement psiElement = (PsiElement)element; |
| return ModuleUtilCore.findModuleForPsiElement(psiElement); |
| } |
| return null; |
| } |
| |
| @NotNull |
| public final Object[] getSelectedElements() { |
| TreePath[] paths = getSelectionPaths(); |
| if (paths == null) return PsiElement.EMPTY_ARRAY; |
| ArrayList<Object> list = new ArrayList<Object>(paths.length); |
| for (TreePath path : paths) { |
| Object lastPathComponent = path.getLastPathComponent(); |
| Object element = getElementFromTreeNode(lastPathComponent); |
| if (element instanceof Object[]) { |
| Collections.addAll(list, (Object[])element); |
| } |
| else if (element != null) { |
| list.add(element); |
| } |
| } |
| return ArrayUtil.toObjectArray(list); |
| } |
| |
| @Nullable |
| public Object getElementFromTreeNode(@Nullable final Object treeNode) { |
| if (treeNode instanceof DefaultMutableTreeNode) { |
| DefaultMutableTreeNode node = (DefaultMutableTreeNode)treeNode; |
| return exhumeElementFromNode(node); |
| } |
| return null; |
| } |
| |
| private TreeNode[] getSelectedTreeNodes(){ |
| TreePath[] paths = getSelectionPaths(); |
| if (paths == null) return null; |
| final List<TreeNode> result = new ArrayList<TreeNode>(); |
| for (TreePath path : paths) { |
| Object lastPathComponent = path.getLastPathComponent(); |
| if (lastPathComponent instanceof DefaultMutableTreeNode) { |
| result.add ( (TreeNode) lastPathComponent); |
| } |
| } |
| return result.toArray(new TreeNode[result.size()]); |
| } |
| |
| |
| protected Object exhumeElementFromNode(final DefaultMutableTreeNode node) { |
| return extractUserObject(node); |
| } |
| |
| public static Object extractUserObject(DefaultMutableTreeNode node) { |
| Object userObject = node.getUserObject(); |
| Object element = null; |
| if (userObject instanceof AbstractTreeNode) { |
| AbstractTreeNode descriptor = (AbstractTreeNode)userObject; |
| element = descriptor.getValue(); |
| } |
| else if (userObject instanceof NodeDescriptor) { |
| NodeDescriptor descriptor = (NodeDescriptor)userObject; |
| element = descriptor.getElement(); |
| if (element instanceof AbstractTreeNode) { |
| element = ((AbstractTreeNode)element).getValue(); |
| } |
| } |
| else if (userObject != null) { |
| element = userObject; |
| } |
| return element; |
| } |
| |
| public AbstractTreeBuilder getTreeBuilder() { |
| return myTreeBuilder; |
| } |
| |
| public void readExternal(Element element) throws InvalidDataException { |
| List<Element> subPanes = element.getChildren(ELEMENT_SUBPANE); |
| for (Element subPane : subPanes) { |
| String subId = subPane.getAttributeValue(ATTRIBUTE_SUBID); |
| TreeState treeState = new TreeState(); |
| treeState.readExternal(subPane); |
| myReadTreeState.put(subId, treeState); |
| } |
| } |
| |
| public void writeExternal(Element element) throws WriteExternalException { |
| saveExpandedPaths(); |
| for (String subId : myReadTreeState.keySet()) { |
| TreeState treeState = myReadTreeState.get(subId); |
| Element subPane = new Element(ELEMENT_SUBPANE); |
| if (subId != null) { |
| subPane.setAttribute(ATTRIBUTE_SUBID, subId); |
| } |
| treeState.writeExternal(subPane); |
| element.addContent(subPane); |
| } |
| } |
| |
| protected void saveExpandedPaths() { |
| if (myTree != null) { |
| TreeState treeState = TreeState.createOn(myTree); |
| myReadTreeState.put(getSubId(), treeState); |
| } |
| } |
| |
| public final void restoreExpandedPaths(){ |
| TreeState treeState = myReadTreeState.get(getSubId()); |
| if (treeState != null) { |
| treeState.applyTo(myTree); |
| } |
| } |
| |
| public void installComparator() { |
| final ProjectView projectView = ProjectView.getInstance(myProject); |
| getTreeBuilder().setNodeDescriptorComparator(new GroupByTypeComparator(projectView, getId())); |
| } |
| |
| public JTree getTree() { |
| return myTree; |
| } |
| |
| public PsiDirectory[] getSelectedDirectories() { |
| final PsiElement[] elements = getSelectedPSIElements(); |
| if (elements.length == 1) { |
| final PsiElement element = elements[0]; |
| if (element instanceof PsiDirectory) { |
| return new PsiDirectory[]{(PsiDirectory)element}; |
| } |
| else if (element instanceof PsiDirectoryContainer) { |
| return ((PsiDirectoryContainer)element).getDirectories(); |
| } |
| else { |
| final PsiFile containingFile = element.getContainingFile(); |
| if (containingFile != null) { |
| final PsiDirectory psiDirectory = containingFile.getContainingDirectory(); |
| if (psiDirectory != null) { |
| return new PsiDirectory[]{psiDirectory}; |
| } |
| final VirtualFile file = containingFile.getVirtualFile(); |
| if (file instanceof VirtualFileWindow) { |
| final VirtualFile delegate = ((VirtualFileWindow)file).getDelegate(); |
| final PsiFile delegatePsiFile = containingFile.getManager().findFile(delegate); |
| if (delegatePsiFile != null && delegatePsiFile.getContainingDirectory() != null) { |
| return new PsiDirectory[] { delegatePsiFile.getContainingDirectory() }; |
| } |
| } |
| return PsiDirectory.EMPTY_ARRAY; |
| } |
| } |
| } |
| else { |
| final DefaultMutableTreeNode selectedNode = getSelectedNode(); |
| if (selectedNode != null) { |
| return getSelectedDirectoriesInAmbiguousCase(selectedNode); |
| } |
| } |
| return PsiDirectory.EMPTY_ARRAY; |
| } |
| |
| protected PsiDirectory[] getSelectedDirectoriesInAmbiguousCase(@NotNull final DefaultMutableTreeNode node) { |
| final Object userObject = node.getUserObject(); |
| if (userObject instanceof AbstractModuleNode) { |
| final Module module = ((AbstractModuleNode)userObject).getValue(); |
| if (module != null) { |
| final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); |
| final VirtualFile[] sourceRoots = moduleRootManager.getSourceRoots(); |
| List<PsiDirectory> dirs = new ArrayList<PsiDirectory>(sourceRoots.length); |
| final PsiManager psiManager = PsiManager.getInstance(myProject); |
| for (final VirtualFile sourceRoot : sourceRoots) { |
| final PsiDirectory directory = psiManager.findDirectory(sourceRoot); |
| if (directory != null) { |
| dirs.add(directory); |
| } |
| } |
| return dirs.toArray(new PsiDirectory[dirs.size()]); |
| } |
| } |
| return PsiDirectory.EMPTY_ARRAY; |
| } |
| |
| // Drag'n'Drop stuff |
| |
| @Nullable |
| public static PsiElement[] getTransferedPsiElements(Transferable transferable) { |
| try { |
| final Object transferData = transferable.getTransferData(DnDEventImpl.ourDataFlavor); |
| if (transferData instanceof TransferableWrapper) { |
| return ((TransferableWrapper)transferData).getPsiElements(); |
| } |
| return null; |
| } |
| catch (Exception e) { |
| return null; |
| } |
| } |
| |
| @Nullable |
| public static TreeNode[] getTransferedTreeNodes(Transferable transferable) { |
| try { |
| final Object transferData = transferable.getTransferData(DnDEventImpl.ourDataFlavor); |
| if (transferData instanceof TransferableWrapper) { |
| return ((TransferableWrapper)transferData).getTreeNodes(); |
| } |
| return null; |
| } |
| catch (Exception e) { |
| return null; |
| } |
| } |
| |
| protected void enableDnD() { |
| if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { |
| myDropTarget = new ProjectViewDropTarget(myTree, new Retriever(){ |
| @Override |
| public PsiElement getPsiElement(@Nullable TreeNode node) { |
| return getPSIElement(getElementFromTreeNode(node)); |
| } |
| |
| @Override |
| public Module getModule(TreeNode treeNode) { |
| return getNodeModule(getElementFromTreeNode(treeNode)); |
| } |
| }, myProject); |
| myDragSource = new MyDragSource(); |
| myDndManager = DnDManager.getInstance(); |
| myDndManager.registerSource(myDragSource, myTree); |
| myDndManager.registerTarget(myDropTarget, myTree); |
| } |
| } |
| |
| public void setTreeBuilder(final AbstractTreeBuilder treeBuilder) { |
| if (treeBuilder != null) { |
| Disposer.register(this, treeBuilder); |
| // needs refactoring for project view first |
| // treeBuilder.setCanYieldUpdate(true); |
| } |
| myTreeBuilder = treeBuilder; |
| } |
| |
| private class MyDragSource implements DnDSource { |
| @Override |
| public boolean canStartDragging(DnDAction action, Point dragOrigin) { |
| if ((action.getActionId() & DnDConstants.ACTION_COPY_OR_MOVE) == 0) return false; |
| final Object[] elements = getSelectedElements(); |
| final PsiElement[] psiElements = getSelectedPSIElements(); |
| DataContext dataContext = DataManager.getInstance().getDataContext(myTree); |
| return psiElements.length > 0 || canDragElements(elements, dataContext, action.getActionId()); |
| } |
| |
| @Override |
| public DnDDragStartBean startDragging(DnDAction action, Point dragOrigin) { |
| final PsiElement[] psiElements = getSelectedPSIElements(); |
| final TreeNode[] nodes = getSelectedTreeNodes(); |
| return new DnDDragStartBean(new TransferableWrapper(){ |
| |
| @Override |
| public List<File> asFileList() { |
| return PsiCopyPasteManager.asFileList(psiElements); |
| } |
| |
| @Override |
| public TreeNode[] getTreeNodes() { |
| return nodes; |
| } |
| |
| @Override |
| public PsiElement[] getPsiElements() { |
| return psiElements; |
| } |
| }); |
| } |
| |
| @Override |
| public Pair<Image, Point> createDraggedImage(DnDAction action, Point dragOrigin) { |
| final TreePath[] paths = getSelectionPaths(); |
| if (paths == null) return null; |
| |
| final int count = paths.length; |
| |
| final JLabel label = new JLabel(String.format("%s item%s", count, count == 1 ? "" : "s")); |
| label.setOpaque(true); |
| label.setForeground(myTree.getForeground()); |
| label.setBackground(myTree.getBackground()); |
| label.setFont(myTree.getFont()); |
| label.setSize(label.getPreferredSize()); |
| final BufferedImage image = UIUtil.createImage(label.getWidth(), label.getHeight(), BufferedImage.TYPE_INT_ARGB); |
| |
| Graphics2D g2 = (Graphics2D)image.getGraphics(); |
| g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); |
| label.paint(g2); |
| g2.dispose(); |
| |
| return new Pair<Image, Point>(image, new Point(-image.getWidth(null), -image.getHeight(null))); |
| } |
| |
| @Override |
| public void dragDropEnd() { |
| } |
| |
| @Override |
| public void dropActionChanged(int gestureModifiers) { |
| } |
| } |
| |
| private static boolean canDragElements(Object[] elements, DataContext dataContext, int dragAction) { |
| for (Object element : elements) { |
| if (element instanceof Module) { |
| return true; |
| } |
| } |
| return dragAction == DnDConstants.ACTION_MOVE && MoveHandler.canMove(dataContext); |
| } |
| |
| @Override |
| public ActionCallback getReady(@NotNull Object requestor) { |
| if (myTreeBuilder == null || myTreeBuilder.isDisposed()) return new ActionCallback.Rejected(); |
| return myTreeBuilder.getUi().getReady(requestor); |
| } |
| } |