distinguish annotation interfaces in Ctrl-hover popup (IDEADEV-40633)
[fedora-idea.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / packaging / PackagingEditorImpl.java
blobf62a3382f76179955c23ad1ee87e8d673451b4c3
1 package com.intellij.openapi.roots.ui.configuration.packaging;
3 import com.intellij.ide.CommonActionsManager;
4 import com.intellij.ide.DefaultTreeExpander;
5 import com.intellij.openapi.actionSystem.*;
6 import com.intellij.openapi.deployment.*;
7 import com.intellij.openapi.module.Module;
8 import com.intellij.openapi.project.Project;
9 import com.intellij.openapi.project.ProjectBundle;
10 import com.intellij.openapi.roots.LibraryOrderEntry;
11 import com.intellij.openapi.roots.OrderEntry;
12 import com.intellij.openapi.roots.libraries.Library;
13 import com.intellij.openapi.roots.ui.configuration.FacetsProvider;
14 import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
15 import com.intellij.openapi.roots.ui.configuration.projectRoot.FindUsagesInProjectStructureActionBase;
16 import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable;
17 import com.intellij.openapi.ui.popup.JBPopupFactory;
18 import com.intellij.openapi.util.Comparing;
19 import com.intellij.openapi.util.Ref;
20 import com.intellij.openapi.wm.IdeFocusManager;
21 import com.intellij.ui.*;
22 import com.intellij.ui.treeStructure.Tree;
23 import com.intellij.ui.awt.RelativePoint;
24 import com.intellij.util.containers.Convertor;
25 import com.intellij.util.ui.tree.TreeUtil;
26 import com.intellij.util.EventDispatcher;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29 import org.jetbrains.annotations.NonNls;
30 import org.jetbrains.annotations.TestOnly;
32 import javax.swing.*;
33 import javax.swing.event.TreeSelectionEvent;
34 import javax.swing.event.TreeSelectionListener;
35 import javax.swing.tree.DefaultTreeModel;
36 import javax.swing.tree.TreePath;
37 import java.awt.*;
38 import java.awt.event.ActionEvent;
39 import java.awt.event.ActionListener;
40 import java.awt.event.MouseAdapter;
41 import java.awt.event.MouseEvent;
42 import java.util.*;
43 import java.util.List;
45 /**
46 * @author nik
48 public class PackagingEditorImpl implements PackagingEditor {
49 private static final Convertor<TreePath, String> SPEED_SEARCH_CONVERTOR = new Convertor<TreePath, String>() {
50 public String convert(final TreePath path) {
51 Object o = path.getLastPathComponent();
52 if (o instanceof PackagingTreeNode) {
53 return ((PackagingTreeNode)o).getSearchName();
55 return "";
58 private final PackagingConfiguration myOriginalConfiguration;
59 private final PackagingConfiguration myModifiedConfiguration;
60 private final ModulesProvider myModulesProvider;
61 private final FacetsProvider myFacetsProvider;
62 private final PackagingEditorPolicy myPolicy;
63 private Tree myTree;
64 private RootNode myRoot;
65 private DefaultTreeModel myTreeModel;
66 private final PackagingTreeBuilder myBuilder;
67 private JPanel myMainPanel;
68 private JPanel myTreePanel;
69 private JButton myAddButton;
70 private JButton myRemoveButton;
71 private JButton myEditButton;
72 private JCheckBox myShowIncludedCheckBox;
73 private JCheckBox myShowLibraryFilesCheckBox;
74 private PackagingArtifact myRootArtifact;
75 private final Project myProject;
76 private PackagingTreeParameters myTreeParameters;
77 private final EventDispatcher<PackagingEditorListener> myDispatcher = EventDispatcher.create(PackagingEditorListener.class);
79 public PackagingEditorImpl(final PackagingConfiguration originalConfiguration,
80 final PackagingConfiguration modifiedConfiguration,
81 final ModulesProvider modulesProvider, final FacetsProvider facetsProvider, final PackagingEditorPolicy policy,
82 final PackagingTreeBuilder builder, final boolean showIncludedCheckboxVisible) {
83 myOriginalConfiguration = originalConfiguration;
84 myModifiedConfiguration = modifiedConfiguration;
85 myModulesProvider = modulesProvider;
86 myFacetsProvider = facetsProvider;
87 myPolicy = policy;
88 myBuilder = builder;
89 myProject = myPolicy.getModule().getProject();
90 setTreeParameters(myBuilder.getDefaultParameters());
92 myAddButton.addActionListener(new ActionListener() {
93 public void actionPerformed(final ActionEvent e) {
94 JBPopupFactory.getInstance().createListPopup(new AddPackagingElementPopupStep(PackagingEditorImpl.this, myPolicy.getAddActions())).showUnderneathOf(myAddButton);
96 });
97 myEditButton.addActionListener(new ActionListener() {
98 public void actionPerformed(final ActionEvent e) {
99 PackagingElementsToEditInfo elementsToEdit = getSelectedElements().getElementsToEdit(myPolicy);
100 if (elementsToEdit != null) {
101 editElement(elementsToEdit);
105 myRemoveButton.addActionListener(new ActionListener() {
106 public void actionPerformed(final ActionEvent e) {
107 removeSelectedElements();
110 ActionListener actionListener = new ActionListener() {
111 public void actionPerformed(final ActionEvent e) {
112 myTreeParameters = new PackagingTreeParameters(myShowIncludedCheckBox.isSelected(), myShowLibraryFilesCheckBox.isSelected());
113 myBuilder.updateParameters(myTreeParameters);
114 rebuildTree();
117 myShowIncludedCheckBox.addActionListener(actionListener);
118 myShowLibraryFilesCheckBox.addActionListener(actionListener);
119 myShowIncludedCheckBox.setVisible(showIncludedCheckboxVisible);
122 public void removeSelectedElements() {
123 SelectedPackagingElements selectedElements = getSelectedElements();
124 if (!selectedElements.showRemovingWarning(this)) return;
126 saveData();
127 for (ContainerElement containerElement : selectedElements.getContainerElements()) {
128 myModifiedConfiguration.removeContainerElement(containerElement);
130 for (PackagingArtifact owner : selectedElements.getOwners()) {
131 ContainerElement element = owner.getContainerElement();
132 if (element != null) {
133 myModifiedConfiguration.removeContainerElement(element);
136 rebuildTree();
139 public PackagingArtifact getRootArtifact() {
140 return myRootArtifact;
143 private SelectedPackagingElements getSelectedElements() {
144 PackagingTreeNode[] treeNodes = myTree.getSelectedNodes(PackagingTreeNode.class, null);
145 return new SelectedPackagingElements(treeNodes);
148 public void addModules(final List<Module> modules) {
149 if (modules.isEmpty()) return;
151 saveData();
152 modules.removeAll(Arrays.asList(myModifiedConfiguration.getContainingIdeaModules()));
153 ContainerElement last = null;
154 for (Module module : modules) {
155 ModuleLink element = DeploymentUtil.getInstance().createModuleLink(module, myPolicy.getModule());
156 addElement(element);
157 last = element;
159 rebuildTree();
160 if (last != null) {
161 selectElement(last, false);
165 private void editElement(final @NotNull PackagingElementsToEditInfo elementsToEdit) {
166 saveData();
167 boolean ok = PackagingElementPropertiesComponent.showDialog(elementsToEdit, myMainPanel, myPolicy, myDispatcher.getMulticaster());
168 if (ok) {
169 rebuildTree();
170 selectElements(elementsToEdit.getElements());
174 @TestOnly
175 @Nullable
176 public PackagingElementPropertiesComponent editSelectedElements() {
177 SelectedPackagingElements selectedElements = getSelectedElements();
178 if (selectedElements == null) return null;
180 PackagingElementsToEditInfo elementsInfo = selectedElements.getElementsToEdit(myPolicy);
181 if (elementsInfo == null) return null;
183 return PackagingElementPropertiesComponent.createPropertiesComponent(elementsInfo, myPolicy, null);
186 private void selectElements(final List<ContainerElement> elements) {
187 //todo[nik]
188 selectElement(elements.get(0), false);
191 public void addElement(final ContainerElement element) {
192 if (myPolicy.isAllowedToPackage(element)) {
193 myPolicy.setDefaultAttributes(element);
194 PackagingMethod method = element.getPackagingMethod();
195 if (method == PackagingMethod.DO_NOT_PACKAGE) {
196 //todo[nik] is it correct?
197 PackagingMethod[] methods = myPolicy.getAllowedPackagingMethods(element);
198 element.setPackagingMethod(methods[0]);
199 element.setURI(myPolicy.suggestDefaultRelativePath(element));
201 myModifiedConfiguration.addOrReplaceElement(element);
205 public void selectElement(@NotNull final ContainerElement toSelect, final boolean requestFocus) {
206 PackagingTreeNode node = findNodeByElement(toSelect);
207 if (node != null) {
208 TreeUtil.selectNode(myTree, node);
209 if (requestFocus) {
210 IdeFocusManager.getInstance(myProject).requestFocus(myTree, true);
215 public void processNewOrderEntries(final Set<OrderEntry> newEntries) {
216 List<Library> libraries = new ArrayList<Library>();
217 for (OrderEntry entry : newEntries) {
218 if (entry instanceof LibraryOrderEntry) {
219 libraries.add(((LibraryOrderEntry)entry).getLibrary());
222 myPolicy.processNewLibraries(this, libraries);
225 public void addListener(@NotNull final PackagingEditorListener listener) {
226 myDispatcher.addListener(listener);
229 public void removeListener(@NotNull final PackagingEditorListener listener) {
230 myDispatcher.removeListener(listener);
233 @TestOnly
234 public boolean selectNodes(@NotNull @NonNls final String... nodeNames) {
235 final List<PackagingTreeNode> toSelect = new ArrayList<PackagingTreeNode>();
236 TreeUtil.traverseDepth(myRoot, new TreeUtil.Traverse() {
237 public boolean accept(final Object node) {
238 if (node instanceof PackagingTreeNode) {
239 PackagingTreeNode packagingNode = (PackagingTreeNode)node;
240 if (Arrays.asList(nodeNames).contains(packagingNode.getOutputFileName())) {
241 toSelect.add(packagingNode);
244 return true;
247 myTree.getSelectionModel().clearSelection();
248 for (PackagingTreeNode node : toSelect) {
249 myTree.getSelectionModel().addSelectionPath(new TreePath(node.getPath()));
251 return toSelect.size() == nodeNames.length;
254 @Nullable
255 private PackagingTreeNode findNodeByElement(final ContainerElement toSelect) {
256 final Ref<PackagingTreeNode> ref = Ref.create(null);
257 TreeUtil.traverseDepth(myRoot, new TreeUtil.Traverse() {
258 public boolean accept(final Object node) {
259 if (node instanceof PackagingTreeNode) {
260 PackagingTreeNode packagingNode = (PackagingTreeNode)node;
261 ContainerElement element = packagingNode.getContainerElement();
262 if (toSelect.equals(element)) {
263 ref.set(packagingNode);
264 return false;
267 return true;
270 return ref.get();
273 public Tree getTree() {
274 return myTree;
277 public void addLibraries(final List<Library> libraries) {
278 if (libraries.isEmpty()) return;
280 saveData();
281 libraries.removeAll(Arrays.asList(myModifiedConfiguration.getContainingLibraries()));
282 ContainerElement last = null;
283 for (Library library : libraries) {
284 LibraryLink libraryLink = DeploymentUtil.getInstance().createLibraryLink(library, myPolicy.getModule());
285 addElement(libraryLink);
286 last = libraryLink;
288 rebuildTree();
289 if (last != null) {
290 selectElement(last, false);
294 public void setTreeParameters(PackagingTreeParameters parameters) {
295 myShowIncludedCheckBox.setSelected(parameters.isShowIncludedContent());
296 myShowLibraryFilesCheckBox.setSelected(parameters.isShowLibraryFiles());
297 myTreeParameters = parameters;
300 public void rebuildTree() {
301 PackagingTreeState state = PackagingTreeState.saveState(myTree);
302 myRoot.removeAllChildren();
303 myRootArtifact = myBuilder.createRootArtifact();
304 PackagingArtifactNode root = PackagingTreeNodeFactoryOld.createArtifactNode(myRootArtifact, myRoot, null);
305 for (ContainerElement element : getPackagedElements()) {
306 myBuilder.createNodes(root, element, null, myTreeParameters);
308 myTreeModel.nodeStructureChanged(myRoot);
309 TreeUtil.sort(myTreeModel, new Comparator<PackagingTreeNode>() {
310 public int compare(final PackagingTreeNode node1, final PackagingTreeNode node2) {
311 double weight1 = node1.getWeight();
312 double weight2 = node2.getWeight();
313 if (weight1 < weight2) return -1;
314 if (weight1 > weight2) return 1;
316 return node1.compareTo(node2);
319 state.restoreState(myTree);
322 public void saveData() {
326 public void moduleStateChanged() {
327 if (myPolicy.removeObsoleteElements(this)) {
328 rebuildTree();
332 public PackagingConfiguration getModifiedConfiguration() {
333 return myModifiedConfiguration;
336 public ContainerElement[] getModifiedElements() {
337 return myModifiedConfiguration.getElements(myModulesProvider, myFacetsProvider, true, true, true);
340 public boolean isModified() {
341 final ContainerElement[] elements1 = getPackagedElements();
342 final ContainerElement[] elements2 = myOriginalConfiguration.getElements(myModulesProvider, myFacetsProvider, true, true, false);
343 return !Comparing.haveEqualElements(elements1, elements2);
346 private ContainerElement[] getPackagedElements() {
347 return myModifiedConfiguration.getElements(myModulesProvider, myFacetsProvider, true, true, false);
350 public void reset() {
351 final ContainerElement[] elements = myOriginalConfiguration.getElements(myModulesProvider, myFacetsProvider, true, true, true);
352 ContainerElement[] newElements = new ContainerElement[elements.length];
353 for (int i = 0; i < elements.length; i++) {
354 newElements[i] = elements[i].clone();
356 myModifiedConfiguration.setElements(newElements);
357 if (myTree != null) {
358 rebuildTree();
362 public JComponent createMainComponent() {
363 myMainPanel.setMinimumSize(new Dimension(-1, 250));
364 myRoot = new RootNode();
365 myTreeModel = new DefaultTreeModel(myRoot);
366 myTree = new Tree(myTreeModel) {
367 @Override
368 public String getToolTipText(final MouseEvent event) {
369 TreePath path = myTree.getPathForLocation(event.getX(), event.getY());
370 if (path != null) {
371 return ((PackagingTreeNode)path.getLastPathComponent()).getTooltipText();
373 return super.getToolTipText();
376 myTree.setRootVisible(false);
377 myTree.setShowsRootHandles(true);
378 myTree.setCellRenderer(new PackagingTreeCellRenderer());
379 myTreePanel.add(ScrollPaneFactory.createScrollPane(myTree), BorderLayout.CENTER);
380 new TreeSpeedSearch(myTree, SPEED_SEARCH_CONVERTOR, true);
381 myTree.addTreeSelectionListener(new TreeSelectionListener() {
382 public void valueChanged(final TreeSelectionEvent e) {
383 updateButtons();
386 myTree.addMouseListener(new PackagingTreeMouseListener());
388 DefaultActionGroup actionGroup = new DefaultActionGroup();
389 actionGroup.add(new MyNavigateAction());
390 actionGroup.add(new MyFindUsagesAction());
392 actionGroup.add(Separator.getInstance());
393 CommonActionsManager actionsManager = CommonActionsManager.getInstance();
394 DefaultTreeExpander treeExpander = new DefaultTreeExpander(myTree);
395 actionGroup.add(actionsManager.createExpandAllAction(treeExpander, myTree));
396 actionGroup.add(actionsManager.createCollapseAllAction(treeExpander, myTree));
398 PopupHandler.installPopupHandler(myTree, actionGroup, ActionPlaces.UNKNOWN, ActionManager.getInstance());
399 TreeToolTipHandler.install(myTree);
400 ToolTipManager.sharedInstance().registerComponent(myTree);
401 rebuildTree();
402 TreeUtil.expandAll(myTree);
403 updateButtons();
404 return myMainPanel;
407 private void updateButtons() {
408 SelectedPackagingElements selectedElements = getSelectedElements();
409 List<ContainerElement> elements = selectedElements.getContainerElements();
410 Set<PackagingArtifact> artifacts = selectedElements.getOwners();
411 myRemoveButton.setEnabled(!elements.isEmpty() || !artifacts.isEmpty());
412 PackagingElementsToEditInfo elementsToEdit = selectedElements.getElementsToEdit(myPolicy);
413 myEditButton.setEnabled(elementsToEdit != null && PackagingElementPropertiesComponent.isEnabled(elementsToEdit));
416 public JPanel getMainPanel() {
417 return myMainPanel;
420 public PackagingTreeNode getRoot() {
421 return myRoot;
424 private void navigate(PackagingTreeNode treeNode) {
425 treeNode.navigate(ModuleStructureConfigurable.getInstance(myProject));
428 private static class RootNode extends PackagingTreeNode {
429 private RootNode() {
430 super(null);
433 @NotNull
434 public String getOutputFileName() {
435 return "";
438 public double getWeight() {
439 return 0;
442 public void render(@NotNull final ColoredTreeCellRenderer renderer) {
445 public boolean canNavigate() {
446 return false;
449 public void navigate(final ModuleStructureConfigurable configurable) {
452 public Object getSourceObject() {
453 return null;
457 private class PackagingTreeMouseListener extends MouseAdapter {
458 @Override
459 public void mouseClicked(final MouseEvent e) {
460 if (e.getClickCount() == 2) {
461 PackagingTreeNode[] nodes = myTree.getSelectedNodes(PackagingTreeNode.class, null);
462 if (nodes.length == 1) {
463 PackagingTreeNode node = nodes[0];
464 if (node.getChildren().isEmpty()) {
465 ContainerElement element = node.getContainerElement();
466 if (element != null) {
467 if (node.getOwner() == null) {
468 editElement(new PackagingElementsToEditInfo(element, myPolicy));
470 else {
471 navigate(node);
480 private static class PackagingTreeCellRenderer extends ColoredTreeCellRenderer {
481 public void customizeCellRenderer(final JTree tree,
482 final Object value,
483 final boolean selected,
484 final boolean expanded,
485 final boolean leaf,
486 final int row,
487 final boolean hasFocus) {
488 PackagingTreeNode node = (PackagingTreeNode)value;
489 node.render(this);
490 setEnabled(tree.isEnabled());
494 private class MyNavigateAction extends AnAction {
495 private MyNavigateAction() {
496 super(ProjectBundle.message("action.name.facet.navigate"));
497 registerCustomShortcutSet(CommonShortcuts.getEditSource(), myTree);
500 public void update(final AnActionEvent e) {
501 PackagingTreeNode[] treeNodes = myTree.getSelectedNodes(PackagingTreeNode.class, null);
502 e.getPresentation().setEnabled(treeNodes.length == 1 && treeNodes[0].canNavigate());
505 public void actionPerformed(final AnActionEvent e) {
506 PackagingTreeNode[] treeNodes = myTree.getSelectedNodes(PackagingTreeNode.class, null);
507 if (treeNodes.length == 1) {
508 navigate(treeNodes[0]);
513 private class MyFindUsagesAction extends FindUsagesInProjectStructureActionBase {
514 public MyFindUsagesAction() {
515 super(myTree, myProject);
518 protected boolean isEnabled() {
519 PackagingTreeNode[] treeNodes = myTree.getSelectedNodes(PackagingTreeNode.class, null);
520 return treeNodes.length == 1 && treeNodes[0].getSourceObject() != null;
523 protected Object getSelectedObject() {
524 PackagingTreeNode[] treeNodes = myTree.getSelectedNodes(PackagingTreeNode.class, null);
525 return treeNodes.length == 1 ? treeNodes[0].getSourceObject() : null;
528 protected RelativePoint getPointToShowResults() {
529 final int selectedRow = myTree.getSelectionRows()[0];
530 final Rectangle rowBounds = myTree.getRowBounds(selectedRow);
531 final Point location = rowBounds.getLocation();
532 location.y += rowBounds.height;
533 return new RelativePoint(myTree, location);