79eaffe012770ed88273a535c67acbd78a784c2a
[idea/community.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / artifacts / LayoutTree.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.roots.ui.configuration.artifacts;
17
18 import com.intellij.ide.dnd.AdvancedDnDSource;
19 import com.intellij.ide.dnd.DnDAction;
20 import com.intellij.ide.dnd.DnDDragStartBean;
21 import com.intellij.ide.dnd.DnDManager;
22 import com.intellij.ide.dnd.aware.DnDAwareTree;
23 import com.intellij.ide.util.treeView.AbstractTreeBuilder;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.project.ProjectBundle;
26 import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.CompositePackagingElementNode;
27 import com.intellij.openapi.roots.ui.configuration.artifacts.nodes.PackagingElementNode;
28 import com.intellij.openapi.util.Pair;
29 import com.intellij.openapi.util.text.StringUtil;
30 import com.intellij.openapi.wm.IdeFocusManager;
31 import com.intellij.packaging.elements.PackagingElement;
32 import com.intellij.packaging.elements.RenameablePackagingElement;
33 import com.intellij.ui.TreeSpeedSearch;
34 import com.intellij.ui.TreeUIHelper;
35 import com.intellij.ui.treeStructure.SimpleNode;
36 import com.intellij.util.containers.ContainerUtil;
37 import com.intellij.util.containers.Convertor;
38 import com.intellij.util.ui.tree.TreeUtil;
39 import org.jetbrains.annotations.Nullable;
40
41 import javax.swing.*;
42 import javax.swing.tree.DefaultMutableTreeNode;
43 import javax.swing.tree.TreePath;
44 import java.awt.*;
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.List;
48
49 /**
50 * @author nik
51 */
52 public class LayoutTree extends SimpleDnDAwareTree implements AdvancedDnDSource {
53   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.artifacts.LayoutTree");
54   private final ArtifactEditorImpl myArtifactsEditor;
55
56   public LayoutTree(ArtifactEditorImpl artifactsEditor) {
57     myArtifactsEditor = artifactsEditor;
58     setRootVisible(true);
59     setShowsRootHandles(false);
60     setCellEditor(new LayoutTreeCellEditor());
61     DnDManager.getInstance().registerSource(this);
62   }
63
64   public void addSubtreeToUpdate(DefaultMutableTreeNode newNode) {
65     AbstractTreeBuilder.getBuilderFor(this).addSubtreeToUpdate(newNode);
66   }
67
68   @Override
69   protected void configureUiHelper(TreeUIHelper helper) {
70     final Convertor<TreePath, String> convertor = new Convertor<TreePath, String>() {
71       public String convert(final TreePath path) {
72         final SimpleNode node = getNodeFor(path);
73         if (node instanceof PackagingElementNode) {
74           return ((PackagingElementNode<?>)node).getElementPresentation().getSearchName();
75         }
76         return "";
77       }
78     };
79     new TreeSpeedSearch(this, convertor, true);
80     helper.installToolTipHandler(this);
81   }
82
83   private List<PackagingElementNode<?>> getNodesToDrag() {
84     return getSelection().getNodes();
85   }
86
87   public boolean canStartDragging(DnDAction action, Point dragOrigin) {
88     return !getNodesToDrag().isEmpty();
89   }
90
91   public DnDDragStartBean startDragging(DnDAction action, Point dragOrigin) {
92     return new DnDDragStartBean(new LayoutNodesDraggingObject(myArtifactsEditor, getNodesToDrag()));
93   }
94
95   public Pair<Image, Point> createDraggedImage(DnDAction action, Point dragOrigin) {
96     final List<PackagingElementNode<?>> nodes = getNodesToDrag();
97     if (nodes.size() == 1) {
98       return DnDAwareTree.getDragImage(this, getPathFor(nodes.get(0)), dragOrigin);
99     }
100     return DnDAwareTree.getDragImage(this, ProjectBundle.message("drag.n.drop.text.0.packaging.elements", nodes.size()), dragOrigin);
101   }
102
103   public void dragDropEnd() {
104   }
105
106   public void dropActionChanged(int gestureModifiers) {
107   }
108
109   public void dispose() {
110     DnDManager.getInstance().unregisterSource(this);
111   }
112
113   public LayoutTreeSelection getSelection() {
114     return new LayoutTreeSelection(this);
115   }
116
117   @Nullable
118   public PackagingElement<?> getElementByPath(TreePath path) {
119     final SimpleNode node = getNodeFor(path);
120     if (node instanceof PackagingElementNode) {
121       final List<? extends PackagingElement<?>> elements = ((PackagingElementNode<?>)node).getPackagingElements();
122       if (elements.size() == 1) {
123         return elements.get(0);
124       }
125     }
126     return null;
127   }
128
129   public PackagingElementNode<?> getRootPackagingNode() {
130     final DefaultMutableTreeNode rootNode = getRootNode();
131     if (rootNode == null) {
132       return null;
133     }
134     return (PackagingElementNode<?>)getNodeFor(new TreePath(rootNode));
135   }
136
137   public DefaultMutableTreeNode getRootNode() {
138     return (DefaultMutableTreeNode)getModel().getRoot();
139   }
140
141   public List<PackagingElementNode<?>> findNodes(final Collection<? extends PackagingElement<?>> elements) {
142     final List<PackagingElementNode<?>> nodes = new ArrayList<PackagingElementNode<?>>();
143     TreeUtil.traverseDepth(getRootNode(), new TreeUtil.Traverse() {
144       public boolean accept(Object node) {
145         final Object userObject = ((DefaultMutableTreeNode)node).getUserObject();
146         if (userObject instanceof PackagingElementNode) {
147           final PackagingElementNode<?> packagingNode = (PackagingElementNode<?>)userObject;
148           final List<? extends PackagingElement<?>> nodeElements = packagingNode.getPackagingElements();
149           if (ContainerUtil.intersects(nodeElements, elements)) {
150             nodes.add(packagingNode);
151           }
152         }
153         return true;
154       }
155     });
156     return nodes;
157   }
158
159   public void addSubtreeToUpdate(final PackagingElementNode elementNode) {
160     final DefaultMutableTreeNode node = TreeUtil.findNodeWithObject(getRootNode(), elementNode);
161     if (node != null) {
162       addSubtreeToUpdate(node);
163     }
164   }
165
166   @Nullable
167   public PackagingElementNode<?> findCompositeNodeByPath(String parentPath) {
168     PackagingElementNode<?> node = getRootPackagingNode();
169     for (String name : StringUtil.split(parentPath, "/")) {
170       final CompositePackagingElementNode child = node.findCompositeChild(name);
171       if (child == null) {
172         return null;
173       }
174       node = child;
175     }
176     return node;
177   }
178
179   private class LayoutTreeCellEditor extends DefaultCellEditor {
180     public LayoutTreeCellEditor() {
181       super(new JTextField());
182     }
183
184     @Override
185     public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
186       final JTextField field = (JTextField)super.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
187       final Object node = ((DefaultMutableTreeNode)value).getUserObject();
188       final PackagingElement<?> element = ((PackagingElementNode)node).getElementIfSingle();
189       LOG.assertTrue(element != null);
190       final String name = ((RenameablePackagingElement)element).getName();
191       field.setText(name);
192       int i = name.lastIndexOf('.');
193       field.setSelectionStart(0);
194       field.setSelectionEnd(i != -1 ? i : name.length());
195       return field;
196     }
197
198     @Override
199     public boolean stopCellEditing() {
200       final String newValue = ((JTextField)editorComponent).getText();
201       final TreePath path = getEditingPath();
202       final Object node = getNodeFor(path);
203       RenameablePackagingElement currentElement = null;
204       if (node instanceof PackagingElementNode) {
205         final PackagingElement<?> element = ((PackagingElementNode)node).getElementIfSingle();
206         if (element instanceof RenameablePackagingElement) {
207           currentElement = (RenameablePackagingElement)element;
208         }
209       }
210       final boolean stopped = super.stopCellEditing();
211       if (stopped && currentElement != null) {
212         final RenameablePackagingElement finalCurrentElement = currentElement;
213         myArtifactsEditor.getLayoutTreeComponent().editLayout(new Runnable() {
214           public void run() {
215             finalCurrentElement.rename(newValue);
216           }
217         });
218         myArtifactsEditor.queueValidation();
219         myArtifactsEditor.getLayoutTreeComponent().updatePropertiesPanel(true);
220         addSubtreeToUpdate((DefaultMutableTreeNode)path.getLastPathComponent());
221         requestFocusToTree();
222       }
223       return stopped;
224     }
225
226     @Override
227     public void cancelCellEditing() {
228       super.cancelCellEditing();
229       requestFocusToTree();
230     }
231
232     private void requestFocusToTree() {
233       IdeFocusManager.getInstance(myArtifactsEditor.getContext().getProject()).requestFocus(LayoutTree.this, true);
234     }
235   }
236 }