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
;
33 import javax
.swing
.event
.TreeSelectionEvent
;
34 import javax
.swing
.event
.TreeSelectionListener
;
35 import javax
.swing
.tree
.DefaultTreeModel
;
36 import javax
.swing
.tree
.TreePath
;
38 import java
.awt
.event
.ActionEvent
;
39 import java
.awt
.event
.ActionListener
;
40 import java
.awt
.event
.MouseAdapter
;
41 import java
.awt
.event
.MouseEvent
;
43 import java
.util
.List
;
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();
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
;
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
;
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
);
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
);
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;
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
);
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;
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());
161 selectElement(last
, false);
165 private void editElement(final @NotNull PackagingElementsToEditInfo elementsToEdit
) {
167 boolean ok
= PackagingElementPropertiesComponent
.showDialog(elementsToEdit
, myMainPanel
, myPolicy
, myDispatcher
.getMulticaster());
170 selectElements(elementsToEdit
.getElements());
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
) {
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
);
208 TreeUtil
.selectNode(myTree
, node
);
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
);
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
);
247 myTree
.getSelectionModel().clearSelection();
248 for (PackagingTreeNode node
: toSelect
) {
249 myTree
.getSelectionModel().addSelectionPath(new TreePath(node
.getPath()));
251 return toSelect
.size() == nodeNames
.length
;
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
);
273 public Tree
getTree() {
277 public void addLibraries(final List
<Library
> libraries
) {
278 if (libraries
.isEmpty()) return;
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
);
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)) {
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) {
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
) {
368 public String
getToolTipText(final MouseEvent event
) {
369 TreePath path
= myTree
.getPathForLocation(event
.getX(), event
.getY());
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
) {
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
);
402 TreeUtil
.expandAll(myTree
);
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() {
420 public PackagingTreeNode
getRoot() {
424 private void navigate(PackagingTreeNode treeNode
) {
425 treeNode
.navigate(ModuleStructureConfigurable
.getInstance(myProject
));
428 private static class RootNode
extends PackagingTreeNode
{
434 public String
getOutputFileName() {
438 public double getWeight() {
442 public void render(@NotNull final ColoredTreeCellRenderer renderer
) {
445 public boolean canNavigate() {
449 public void navigate(final ModuleStructureConfigurable configurable
) {
452 public Object
getSourceObject() {
457 private class PackagingTreeMouseListener
extends MouseAdapter
{
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
));
480 private static class PackagingTreeCellRenderer
extends ColoredTreeCellRenderer
{
481 public void customizeCellRenderer(final JTree tree
,
483 final boolean selected
,
484 final boolean expanded
,
487 final boolean hasFocus
) {
488 PackagingTreeNode node
= (PackagingTreeNode
)value
;
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
);