find usages & validation in project structure reworked
[fedora-idea.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / artifacts / ArtifactEditorImpl.java
blobffa8666b9bd566b4eea7eb5dd8d332f05093c03e
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.openapi.roots.ui.configuration.artifacts;
18 import com.intellij.ide.CommonActionsManager;
19 import com.intellij.ide.DataManager;
20 import com.intellij.ide.DefaultTreeExpander;
21 import com.intellij.ide.impl.TypeSafeDataProviderAdapter;
22 import com.intellij.openapi.actionSystem.*;
23 import com.intellij.openapi.compiler.CompilerBundle;
24 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.project.ProjectBundle;
27 import com.intellij.openapi.roots.libraries.Library;
28 import com.intellij.openapi.roots.ui.configuration.artifacts.actions.*;
29 import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.LibrarySourceItem;
30 import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.SourceItemsTree;
31 import com.intellij.openapi.ui.FixedSizeButton;
32 import com.intellij.openapi.ui.Splitter;
33 import com.intellij.openapi.ui.TextFieldWithBrowseButton;
34 import com.intellij.openapi.util.Comparing;
35 import com.intellij.openapi.util.Disposer;
36 import com.intellij.openapi.util.IconLoader;
37 import com.intellij.openapi.util.io.FileUtil;
38 import com.intellij.packaging.artifacts.Artifact;
39 import com.intellij.packaging.artifacts.ModifiableArtifact;
40 import com.intellij.packaging.elements.ComplexPackagingElementType;
41 import com.intellij.packaging.elements.CompositePackagingElement;
42 import com.intellij.packaging.elements.PackagingElementFactory;
43 import com.intellij.packaging.elements.PackagingElementType;
44 import com.intellij.packaging.impl.artifacts.ArtifactUtil;
45 import com.intellij.packaging.impl.elements.ArchivePackagingElement;
46 import com.intellij.packaging.ui.ManifestFileConfiguration;
47 import com.intellij.ui.PopupHandler;
48 import com.intellij.ui.ScrollPaneFactory;
49 import com.intellij.ui.TabbedPaneWrapper;
50 import com.intellij.ui.TreeToolTipHandler;
51 import com.intellij.util.EventDispatcher;
52 import com.intellij.util.Icons;
53 import com.intellij.util.ui.ThreeStateCheckBox;
54 import org.jetbrains.annotations.NotNull;
55 import org.jetbrains.annotations.Nullable;
57 import javax.swing.*;
58 import javax.swing.border.Border;
59 import java.awt.*;
60 import java.awt.event.ActionEvent;
61 import java.awt.event.ActionListener;
62 import java.util.ArrayList;
63 import java.util.Collections;
64 import java.util.List;
66 /**
67 * @author nik
69 public class ArtifactEditorImpl implements ArtifactEditorEx {
70 private JPanel myMainPanel;
71 private JCheckBox myBuildOnMakeCheckBox;
72 private TextFieldWithBrowseButton myOutputDirectoryField;
73 private JPanel myEditorPanel;
74 private JPanel myErrorPanelPlace;
75 private ThreeStateCheckBox myShowContentCheckBox;
76 private FixedSizeButton myShowSpecificContentOptionsButton;
77 private ActionGroup myShowSpecificContentOptionsGroup;
78 private Splitter mySplitter;
79 private final Project myProject;
80 private final ComplexElementSubstitutionParameters mySubstitutionParameters = new ComplexElementSubstitutionParameters();
81 private final EventDispatcher<ArtifactEditorListener> myDispatcher = EventDispatcher.create(ArtifactEditorListener.class);
82 private final ArtifactEditorContextImpl myContext;
83 private SourceItemsTree mySourceItemsTree;
84 private final Artifact myOriginalArtifact;
85 private final LayoutTreeComponent myLayoutTreeComponent;
86 private TabbedPaneWrapper myTabbedPane;
87 private ArtifactPropertiesEditors myPropertiesEditors;
88 private ArtifactValidationManagerImpl myValidationManager;
90 public ArtifactEditorImpl(final ArtifactsStructureConfigurableContext context, Artifact artifact) {
91 myContext = new ArtifactEditorContextImpl(context, this);
92 myOriginalArtifact = artifact;
93 myProject = context.getProject();
94 mySourceItemsTree = new SourceItemsTree(myContext, this);
95 myLayoutTreeComponent = new LayoutTreeComponent(this, mySubstitutionParameters, myContext, myOriginalArtifact);
96 myPropertiesEditors = new ArtifactPropertiesEditors(myContext, myOriginalArtifact);
97 Disposer.register(this, mySourceItemsTree);
98 Disposer.register(this, myLayoutTreeComponent);
99 myBuildOnMakeCheckBox.setSelected(artifact.isBuildOnMake());
100 final String outputPath = artifact.getOutputPath();
101 myOutputDirectoryField.addBrowseFolderListener(CompilerBundle.message("dialog.title.output.directory.for.artifact"),
102 CompilerBundle.message("chooser.description.select.output.directory.for.0.artifact",
103 getArtifact().getName()), myProject,
104 FileChooserDescriptorFactory.createSingleFolderDescriptor());
105 myShowSpecificContentOptionsGroup = createShowSpecificContentOptionsGroup();
106 myShowSpecificContentOptionsButton.addActionListener(new ActionListener() {
107 public void actionPerformed(ActionEvent e) {
108 ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, myShowSpecificContentOptionsGroup).getComponent().show(myShowSpecificContentOptionsButton, 0, 0);
111 setOutputPath(outputPath);
112 myValidationManager = new ArtifactValidationManagerImpl(this);
113 myContext.setValidationManager(myValidationManager);
114 updateShowContentCheckbox();
117 private ActionGroup createShowSpecificContentOptionsGroup() {
118 final DefaultActionGroup group = new DefaultActionGroup();
119 for (ComplexPackagingElementType<?> type : PackagingElementFactory.getInstance().getComplexElementTypes()) {
120 group.add(new ToggleShowElementContentAction(type, this));
122 return group;
125 private void setOutputPath(@Nullable String outputPath) {
126 myOutputDirectoryField.setText(outputPath != null ? FileUtil.toSystemDependentName(outputPath) : null);
129 public void apply() {
130 final ModifiableArtifact modifiableArtifact = myContext.getModifiableArtifactModel().getOrCreateModifiableArtifact(myOriginalArtifact);
131 modifiableArtifact.setBuildOnMake(myBuildOnMakeCheckBox.isSelected());
132 modifiableArtifact.setOutputPath(getConfiguredOutputPath());
133 myPropertiesEditors.applyProperties();
134 myLayoutTreeComponent.saveElementProperties();
137 @Nullable
138 private String getConfiguredOutputPath() {
139 String outputPath = FileUtil.toSystemIndependentName(myOutputDirectoryField.getText().trim());
140 if (outputPath.length() == 0) {
141 outputPath = null;
143 return outputPath;
146 public SourceItemsTree getSourceItemsTree() {
147 return mySourceItemsTree;
150 public void addListener(@NotNull final ArtifactEditorListener listener) {
151 myDispatcher.addListener(listener);
154 public ArtifactEditorContextImpl getContext() {
155 return myContext;
158 public void removeListener(@NotNull final ArtifactEditorListener listener) {
159 myDispatcher.removeListener(listener);
162 public Artifact getArtifact() {
163 return myContext.getArtifactModel().getArtifactByOriginal(myOriginalArtifact);
166 public CompositePackagingElement<?> getRootElement() {
167 return myLayoutTreeComponent.getRootElement();
170 public void rebuildTries() {
171 myLayoutTreeComponent.rebuildTree();
172 mySourceItemsTree.rebuildTree();
175 public void queueValidation() {
176 myValidationManager.queueValidation();
179 public JComponent createMainComponent() {
180 mySourceItemsTree.initTree();
181 myLayoutTreeComponent.initTree();
182 myMainPanel.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, new TypeSafeDataProviderAdapter(new MyDataProvider()));
184 myErrorPanelPlace.add(myValidationManager.getMainErrorPanel(), BorderLayout.CENTER);
186 mySplitter = new Splitter(false);
187 final JPanel leftPanel = new JPanel(new BorderLayout());
188 leftPanel.add(myLayoutTreeComponent.getTreePanel(), BorderLayout.CENTER);
189 final Border border = BorderFactory.createEmptyBorder(3, 3, 3, 3);
190 leftPanel.setBorder(border);
191 mySplitter.setFirstComponent(leftPanel);
193 final JPanel rightPanel = new JPanel(new BorderLayout());
194 final JPanel rightTopPanel = new JPanel(new BorderLayout());
195 rightTopPanel.add(new JLabel("Available Elements (drag'n'drop to layout tree)"), BorderLayout.SOUTH);
196 rightPanel.add(rightTopPanel, BorderLayout.NORTH);
197 rightPanel.add(ScrollPaneFactory.createScrollPane(mySourceItemsTree.getTree()), BorderLayout.CENTER);
198 rightPanel.add(new JPanel(), BorderLayout.SOUTH);
199 rightPanel.setBorder(border);
200 mySplitter.setSecondComponent(rightPanel);
203 myShowContentCheckBox.addActionListener(new ActionListener() {
204 public void actionPerformed(ActionEvent e) {
205 final ThreeStateCheckBox.State state = myShowContentCheckBox.getState();
206 if (state == ThreeStateCheckBox.State.SELECTED) {
207 mySubstitutionParameters.setSubstituteAll();
209 else if (state == ThreeStateCheckBox.State.NOT_SELECTED) {
210 mySubstitutionParameters.setSubstituteNone();
212 myShowContentCheckBox.setThirdStateEnabled(false);
213 myLayoutTreeComponent.rebuildTree();
217 ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, createToolbarActionGroup(), true);
218 leftPanel.add(toolbar.getComponent(), BorderLayout.NORTH);
219 rightTopPanel.setPreferredSize(new Dimension(-1, toolbar.getComponent().getPreferredSize().height));
221 myTabbedPane = new TabbedPaneWrapper(this);
222 myTabbedPane.addTab("Output Layout", mySplitter);
223 myPropertiesEditors.addTabs(myTabbedPane);
224 myEditorPanel.add(myTabbedPane.getComponent(), BorderLayout.CENTER);
226 final LayoutTree tree = myLayoutTreeComponent.getLayoutTree();
227 new ShowAddPackagingElementPopupAction(this).registerCustomShortcutSet(CommonShortcuts.getNew(), tree);
228 PopupHandler.installPopupHandler(tree, createPopupActionGroup(), ActionPlaces.UNKNOWN, ActionManager.getInstance());
229 TreeToolTipHandler.install(tree);
230 ToolTipManager.sharedInstance().registerComponent(tree);
231 rebuildTries();
232 return getMainComponent();
235 public void updateShowContentCheckbox() {
236 final ThreeStateCheckBox.State state;
237 if (mySubstitutionParameters.isAllSubstituted()) {
238 state = ThreeStateCheckBox.State.SELECTED;
240 else if (mySubstitutionParameters.isNoneSubstituted()) {
241 state = ThreeStateCheckBox.State.NOT_SELECTED;
243 else {
244 state = ThreeStateCheckBox.State.DONT_CARE;
246 myShowContentCheckBox.setThirdStateEnabled(state == ThreeStateCheckBox.State.DONT_CARE);
247 myShowContentCheckBox.setState(state);
250 private DefaultActionGroup createToolbarActionGroup() {
251 final DefaultActionGroup toolbarActionGroup = new DefaultActionGroup();
253 final List<AnAction> createActions = new ArrayList<AnAction>(createNewElementActions());
254 for (AnAction createAction : createActions) {
255 toolbarActionGroup.add(createAction);
258 toolbarActionGroup.add(new RemovePackagingElementAction(this));
259 toolbarActionGroup.add(Separator.getInstance());
260 toolbarActionGroup.add(new SortElementsToggleAction(this.getLayoutTreeComponent()));
261 toolbarActionGroup.add(new MoveElementAction(myLayoutTreeComponent, "Move Up", "", IconLoader.getIcon("/actions/moveUp.png"), -1));
262 toolbarActionGroup.add(new MoveElementAction(myLayoutTreeComponent, "Move Down", "", IconLoader.getIcon("/actions/moveDown.png"), 1));
263 return toolbarActionGroup;
266 public List<AnAction> createNewElementActions() {
267 final List<AnAction> createActions = new ArrayList<AnAction>();
268 AddCompositeElementAction.addCompositeCreateActions(createActions, this);
269 createActions.add(createAddNonCompositeElementGroup());
270 return createActions;
273 private DefaultActionGroup createPopupActionGroup() {
274 final LayoutTree tree = myLayoutTreeComponent.getLayoutTree();
276 DefaultActionGroup popupActionGroup = new DefaultActionGroup();
277 final List<AnAction> createActions = new ArrayList<AnAction>();
278 AddCompositeElementAction.addCompositeCreateActions(createActions, this);
279 for (AnAction createAction : createActions) {
280 popupActionGroup.add(createAction);
282 popupActionGroup.add(createAddNonCompositeElementGroup());
283 final RemovePackagingElementAction removeAction = new RemovePackagingElementAction(this);
284 removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, tree);
285 popupActionGroup.add(removeAction);
286 popupActionGroup.add(new ExtractArtifactAction(this));
287 popupActionGroup.add(new InlineArtifactAction(this));
288 popupActionGroup.add(new RenamePackagingElementAction(this));
289 popupActionGroup.add(Separator.getInstance());
290 popupActionGroup.add(new HideContentAction(this));
291 popupActionGroup.add(new ArtifactEditorNavigateAction(myLayoutTreeComponent));
292 popupActionGroup.add(new ArtifactEditorFindUsagesAction(myLayoutTreeComponent, myProject));
294 popupActionGroup.add(Separator.getInstance());
295 CommonActionsManager actionsManager = CommonActionsManager.getInstance();
296 DefaultTreeExpander treeExpander = new DefaultTreeExpander(tree);
297 popupActionGroup.add(actionsManager.createExpandAllAction(treeExpander, tree));
298 popupActionGroup.add(actionsManager.createCollapseAllAction(treeExpander, tree));
299 return popupActionGroup;
302 public ComplexElementSubstitutionParameters getSubstitutionParameters() {
303 return mySubstitutionParameters;
306 private ActionGroup createAddNonCompositeElementGroup() {
307 DefaultActionGroup group = new DefaultActionGroup(ProjectBundle.message("artifacts.add.copy.action"), true);
308 group.getTemplatePresentation().setIcon(Icons.ADD_ICON);
309 for (PackagingElementType<?> type : PackagingElementFactory.getInstance().getNonCompositeElementTypes()) {
310 group.add(new AddNewPackagingElementAction(type, this));
312 return group;
315 public JComponent getMainComponent() {
316 return myMainPanel;
319 public void addNewPackagingElement(@NotNull PackagingElementType<?> type) {
320 myLayoutTreeComponent.addNewPackagingElement(type);
321 mySourceItemsTree.rebuildTree();
324 public void removeSelectedElements() {
325 myLayoutTreeComponent.removeSelectedElements();
328 public boolean isModified() {
329 return myBuildOnMakeCheckBox.isSelected() != myOriginalArtifact.isBuildOnMake()
330 || !Comparing.equal(getConfiguredOutputPath(), myOriginalArtifact.getOutputPath())
331 || myPropertiesEditors.isModified()
332 || myLayoutTreeComponent.isPropertiesModified();
335 public void dispose() {
338 public LayoutTreeComponent getLayoutTreeComponent() {
339 return myLayoutTreeComponent;
342 public void updateOutputPath(@NotNull String oldArtifactName, @NotNull final String newArtifactName) {
343 final String oldDefaultPath = ArtifactUtil.getDefaultArtifactOutputPath(oldArtifactName, myProject);
344 if (Comparing.equal(oldDefaultPath, getConfiguredOutputPath())) {
345 setOutputPath(ArtifactUtil.getDefaultArtifactOutputPath(newArtifactName, myProject));
346 final CompositePackagingElement<?> root = getRootElement();
347 if (root instanceof ArchivePackagingElement) {
348 final String name = ((ArchivePackagingElement)root).getArchiveFileName();
349 final String fileName = FileUtil.getNameWithoutExtension(name);
350 final String extension = FileUtil.getExtension(name);
351 if (fileName.equals(oldArtifactName) && extension.length() > 0) {
352 myLayoutTreeComponent.editLayout(new Runnable() {
353 public void run() {
354 ((ArchivePackagingElement)getRootElement()).setArchiveFileName(newArtifactName + "." + extension);
357 myLayoutTreeComponent.updateTreeNodesPresentation();
363 public void putLibraryIntoDefaultLocation(@NotNull Library library) {
364 myLayoutTreeComponent.putIntoDefaultLocations(Collections.singletonList(new LibrarySourceItem(library)));
367 public void addToClasspath(CompositePackagingElement<?> element, List<String> classpath) {
368 myLayoutTreeComponent.saveElementProperties();
369 final ManifestFileConfiguration manifest = myContext.getManifestFile(element, getArtifact().getArtifactType());
370 manifest.addToClasspath(classpath);
371 myLayoutTreeComponent.resetElementProperties();
374 private class MyDataProvider implements TypeSafeDataProvider {
375 public void calcData(DataKey key, DataSink sink) {
376 if (ARTIFACTS_EDITOR_KEY.equals(key)) {
377 sink.put(ARTIFACTS_EDITOR_KEY, ArtifactEditorImpl.this);