IDEADEV-41116: exploded war artefact: add warning for dependent module
[fedora-idea.git] / java / idea-ui / src / com / intellij / openapi / roots / ui / configuration / artifacts / ArtifactEditorImpl.java
blob5f17e12c671f93ee20c22f99d296b7830bd65491
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.module.Module;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.project.ProjectBundle;
28 import com.intellij.openapi.roots.libraries.Library;
29 import com.intellij.openapi.roots.ui.configuration.artifacts.actions.*;
30 import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.LibrarySourceItem;
31 import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.ModuleOutputSourceItem;
32 import com.intellij.openapi.roots.ui.configuration.artifacts.sourceItems.SourceItemsTree;
33 import com.intellij.openapi.ui.FixedSizeButton;
34 import com.intellij.openapi.ui.Splitter;
35 import com.intellij.openapi.ui.TextFieldWithBrowseButton;
36 import com.intellij.openapi.util.Comparing;
37 import com.intellij.openapi.util.Disposer;
38 import com.intellij.openapi.util.IconLoader;
39 import com.intellij.openapi.util.io.FileUtil;
40 import com.intellij.openapi.vfs.VirtualFile;
41 import com.intellij.packaging.artifacts.Artifact;
42 import com.intellij.packaging.artifacts.ArtifactType;
43 import com.intellij.packaging.artifacts.ModifiableArtifact;
44 import com.intellij.packaging.elements.ComplexPackagingElementType;
45 import com.intellij.packaging.elements.CompositePackagingElement;
46 import com.intellij.packaging.elements.PackagingElementFactory;
47 import com.intellij.packaging.elements.PackagingElementType;
48 import com.intellij.packaging.impl.artifacts.ArtifactUtil;
49 import com.intellij.packaging.impl.elements.ArchivePackagingElement;
50 import com.intellij.packaging.impl.elements.ManifestFileUtil;
51 import com.intellij.packaging.ui.ManifestFileConfiguration;
52 import com.intellij.ui.PopupHandler;
53 import com.intellij.ui.ScrollPaneFactory;
54 import com.intellij.ui.TabbedPaneWrapper;
55 import com.intellij.ui.TreeToolTipHandler;
56 import com.intellij.util.EventDispatcher;
57 import com.intellij.util.Icons;
58 import com.intellij.util.ui.ThreeStateCheckBox;
59 import org.jetbrains.annotations.NotNull;
60 import org.jetbrains.annotations.Nullable;
62 import javax.swing.*;
63 import javax.swing.border.Border;
64 import java.awt.*;
65 import java.awt.event.ActionEvent;
66 import java.awt.event.ActionListener;
67 import java.util.ArrayList;
68 import java.util.Collections;
69 import java.util.List;
71 /**
72 * @author nik
74 public class ArtifactEditorImpl implements ArtifactEditorEx {
75 private JPanel myMainPanel;
76 private JCheckBox myBuildOnMakeCheckBox;
77 private TextFieldWithBrowseButton myOutputDirectoryField;
78 private JPanel myEditorPanel;
79 private JPanel myErrorPanelPlace;
80 private ThreeStateCheckBox myShowContentCheckBox;
81 private FixedSizeButton myShowSpecificContentOptionsButton;
82 private ActionGroup myShowSpecificContentOptionsGroup;
83 private final Project myProject;
84 private final ComplexElementSubstitutionParameters mySubstitutionParameters = new ComplexElementSubstitutionParameters();
85 private final EventDispatcher<ArtifactEditorListener> myDispatcher = EventDispatcher.create(ArtifactEditorListener.class);
86 private final ArtifactEditorContextImpl myContext;
87 private SourceItemsTree mySourceItemsTree;
88 private final Artifact myOriginalArtifact;
89 private final LayoutTreeComponent myLayoutTreeComponent;
90 private TabbedPaneWrapper myTabbedPane;
91 private ArtifactPropertiesEditors myPropertiesEditors;
92 private ArtifactValidationManagerImpl myValidationManager;
94 public ArtifactEditorImpl(final @NotNull ArtifactsStructureConfigurableContext context, @NotNull Artifact artifact, @NotNull ArtifactEditorSettings settings) {
95 myContext = new ArtifactEditorContextImpl(context, this);
96 myOriginalArtifact = artifact;
97 myProject = context.getProject();
98 mySubstitutionParameters.setTypesToShowContent(settings.getTypesToShowContent());
99 mySourceItemsTree = new SourceItemsTree(myContext, this);
100 myLayoutTreeComponent = new LayoutTreeComponent(this, mySubstitutionParameters, myContext, myOriginalArtifact, settings.isSortElements());
101 myPropertiesEditors = new ArtifactPropertiesEditors(myContext, myOriginalArtifact, myOriginalArtifact);
102 Disposer.register(this, mySourceItemsTree);
103 Disposer.register(this, myLayoutTreeComponent);
104 myBuildOnMakeCheckBox.setSelected(artifact.isBuildOnMake());
105 final String outputPath = artifact.getOutputPath();
106 myOutputDirectoryField.addBrowseFolderListener(CompilerBundle.message("dialog.title.output.directory.for.artifact"),
107 CompilerBundle.message("chooser.description.select.output.directory.for.0.artifact",
108 getArtifact().getName()), myProject,
109 FileChooserDescriptorFactory.createSingleFolderDescriptor());
110 myShowSpecificContentOptionsGroup = createShowSpecificContentOptionsGroup();
111 myShowSpecificContentOptionsButton.addActionListener(new ActionListener() {
112 public void actionPerformed(ActionEvent e) {
113 ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, myShowSpecificContentOptionsGroup).getComponent().show(myShowSpecificContentOptionsButton, 0, 0);
116 setOutputPath(outputPath);
117 myValidationManager = new ArtifactValidationManagerImpl(this);
118 updateShowContentCheckbox();
121 private ActionGroup createShowSpecificContentOptionsGroup() {
122 final DefaultActionGroup group = new DefaultActionGroup();
123 for (ComplexPackagingElementType<?> type : PackagingElementFactory.getInstance().getComplexElementTypes()) {
124 group.add(new ToggleShowElementContentAction(type, this));
126 return group;
129 private void setOutputPath(@Nullable String outputPath) {
130 myOutputDirectoryField.setText(outputPath != null ? FileUtil.toSystemDependentName(outputPath) : null);
133 public void apply() {
134 final ModifiableArtifact modifiableArtifact = myContext.getOrCreateModifiableArtifactModel().getOrCreateModifiableArtifact(myOriginalArtifact);
135 modifiableArtifact.setBuildOnMake(myBuildOnMakeCheckBox.isSelected());
136 modifiableArtifact.setOutputPath(getConfiguredOutputPath());
137 myPropertiesEditors.applyProperties();
138 myLayoutTreeComponent.saveElementProperties();
141 @Nullable
142 private String getConfiguredOutputPath() {
143 String outputPath = FileUtil.toSystemIndependentName(myOutputDirectoryField.getText().trim());
144 if (outputPath.length() == 0) {
145 outputPath = null;
147 return outputPath;
150 public SourceItemsTree getSourceItemsTree() {
151 return mySourceItemsTree;
154 public void addListener(@NotNull final ArtifactEditorListener listener) {
155 myDispatcher.addListener(listener);
158 public ArtifactEditorContextImpl getContext() {
159 return myContext;
162 public void removeListener(@NotNull final ArtifactEditorListener listener) {
163 myDispatcher.removeListener(listener);
166 public Artifact getArtifact() {
167 return myContext.getArtifactModel().getArtifactByOriginal(myOriginalArtifact);
170 public CompositePackagingElement<?> getRootElement() {
171 return myLayoutTreeComponent.getRootElement();
174 public void rebuildTries() {
175 myLayoutTreeComponent.rebuildTree();
176 mySourceItemsTree.rebuildTree();
179 public void queueValidation() {
180 myContext.queueValidation();
183 public JComponent createMainComponent() {
184 mySourceItemsTree.initTree();
185 myLayoutTreeComponent.initTree();
186 myMainPanel.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, new TypeSafeDataProviderAdapter(new MyDataProvider()));
188 myErrorPanelPlace.add(myValidationManager.getMainErrorPanel(), BorderLayout.CENTER);
190 Splitter splitter = new Splitter(false);
191 final JPanel leftPanel = new JPanel(new BorderLayout());
192 leftPanel.add(myLayoutTreeComponent.getTreePanel(), BorderLayout.CENTER);
193 final Border border = BorderFactory.createEmptyBorder(3, 3, 3, 3);
194 leftPanel.setBorder(border);
195 splitter.setFirstComponent(leftPanel);
197 final JPanel rightPanel = new JPanel(new BorderLayout());
198 final JPanel rightTopPanel = new JPanel(new BorderLayout());
199 rightTopPanel.add(new JLabel("Available Elements (drag'n'drop to layout tree)"), BorderLayout.SOUTH);
200 rightPanel.add(rightTopPanel, BorderLayout.NORTH);
201 rightPanel.add(ScrollPaneFactory.createScrollPane(mySourceItemsTree.getTree()), BorderLayout.CENTER);
202 rightPanel.setBorder(border);
203 splitter.setSecondComponent(rightPanel);
206 myShowContentCheckBox.addActionListener(new ActionListener() {
207 public void actionPerformed(ActionEvent e) {
208 final ThreeStateCheckBox.State state = myShowContentCheckBox.getState();
209 if (state == ThreeStateCheckBox.State.SELECTED) {
210 mySubstitutionParameters.setSubstituteAll();
212 else if (state == ThreeStateCheckBox.State.NOT_SELECTED) {
213 mySubstitutionParameters.setSubstituteNone();
215 myShowContentCheckBox.setThirdStateEnabled(false);
216 myLayoutTreeComponent.rebuildTree();
217 onShowContentSettingsChanged();
221 ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, createToolbarActionGroup(), true);
222 leftPanel.add(toolbar.getComponent(), BorderLayout.NORTH);
223 rightTopPanel.setPreferredSize(new Dimension(-1, toolbar.getComponent().getPreferredSize().height));
225 myTabbedPane = new TabbedPaneWrapper(this);
226 myTabbedPane.addTab("Output Layout", splitter);
227 myPropertiesEditors.addTabs(myTabbedPane);
228 myEditorPanel.add(myTabbedPane.getComponent(), BorderLayout.CENTER);
230 final LayoutTree tree = myLayoutTreeComponent.getLayoutTree();
231 new ShowAddPackagingElementPopupAction(this).registerCustomShortcutSet(CommonShortcuts.getNew(), tree);
232 PopupHandler.installPopupHandler(tree, createPopupActionGroup(), ActionPlaces.UNKNOWN, ActionManager.getInstance());
233 TreeToolTipHandler.install(tree);
234 ToolTipManager.sharedInstance().registerComponent(tree);
235 rebuildTries();
236 return getMainComponent();
239 private void onShowContentSettingsChanged() {
240 ((ArtifactsStructureConfigurableContextImpl)myContext.getParent()).getDefaultSettings().setTypesToShowContent(mySubstitutionParameters.getTypesToSubstitute());
243 public void updateShowContentCheckbox() {
244 final ThreeStateCheckBox.State state;
245 if (mySubstitutionParameters.isAllSubstituted()) {
246 state = ThreeStateCheckBox.State.SELECTED;
248 else if (mySubstitutionParameters.isNoneSubstituted()) {
249 state = ThreeStateCheckBox.State.NOT_SELECTED;
251 else {
252 state = ThreeStateCheckBox.State.DONT_CARE;
254 myShowContentCheckBox.setThirdStateEnabled(state == ThreeStateCheckBox.State.DONT_CARE);
255 myShowContentCheckBox.setState(state);
256 onShowContentSettingsChanged();
259 public ArtifactEditorSettings createSettings() {
260 return new ArtifactEditorSettings(myLayoutTreeComponent.isSortElements(), mySubstitutionParameters.getTypesToSubstitute());
263 private DefaultActionGroup createToolbarActionGroup() {
264 final DefaultActionGroup toolbarActionGroup = new DefaultActionGroup();
266 final List<AnAction> createActions = new ArrayList<AnAction>(createNewElementActions());
267 for (AnAction createAction : createActions) {
268 toolbarActionGroup.add(createAction);
271 toolbarActionGroup.add(new RemovePackagingElementAction(this));
272 toolbarActionGroup.add(Separator.getInstance());
273 toolbarActionGroup.add(new SortElementsToggleAction(this.getLayoutTreeComponent()));
274 toolbarActionGroup.add(new MovePackagingElementAction(myLayoutTreeComponent, "Move Up", "", IconLoader.getIcon("/actions/moveUp.png"), -1));
275 toolbarActionGroup.add(new MovePackagingElementAction(myLayoutTreeComponent, "Move Down", "", IconLoader.getIcon("/actions/moveDown.png"), 1));
276 return toolbarActionGroup;
279 public List<AnAction> createNewElementActions() {
280 final List<AnAction> createActions = new ArrayList<AnAction>();
281 AddCompositeElementAction.addCompositeCreateActions(createActions, this);
282 createActions.add(createAddNonCompositeElementGroup());
283 return createActions;
286 private DefaultActionGroup createPopupActionGroup() {
287 final LayoutTree tree = myLayoutTreeComponent.getLayoutTree();
289 DefaultActionGroup popupActionGroup = new DefaultActionGroup();
290 final List<AnAction> createActions = new ArrayList<AnAction>();
291 AddCompositeElementAction.addCompositeCreateActions(createActions, this);
292 for (AnAction createAction : createActions) {
293 popupActionGroup.add(createAction);
295 popupActionGroup.add(createAddNonCompositeElementGroup());
296 final RemovePackagingElementAction removeAction = new RemovePackagingElementAction(this);
297 removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, tree);
298 popupActionGroup.add(removeAction);
299 popupActionGroup.add(new ExtractArtifactAction(this));
300 popupActionGroup.add(new InlineArtifactAction(this));
301 popupActionGroup.add(new RenamePackagingElementAction(this));
302 popupActionGroup.add(Separator.getInstance());
303 popupActionGroup.add(new HideContentAction(this));
304 popupActionGroup.add(new LayoutTreeNavigateAction(myLayoutTreeComponent));
305 popupActionGroup.add(new LayoutTreeFindUsagesAction(myLayoutTreeComponent, myProject, myContext.getParent()));
307 popupActionGroup.add(Separator.getInstance());
308 CommonActionsManager actionsManager = CommonActionsManager.getInstance();
309 DefaultTreeExpander treeExpander = new DefaultTreeExpander(tree);
310 popupActionGroup.add(actionsManager.createExpandAllAction(treeExpander, tree));
311 popupActionGroup.add(actionsManager.createCollapseAllAction(treeExpander, tree));
312 return popupActionGroup;
315 public ComplexElementSubstitutionParameters getSubstitutionParameters() {
316 return mySubstitutionParameters;
319 private ActionGroup createAddNonCompositeElementGroup() {
320 DefaultActionGroup group = new DefaultActionGroup(ProjectBundle.message("artifacts.add.copy.action"), true);
321 group.getTemplatePresentation().setIcon(Icons.ADD_ICON);
322 for (PackagingElementType<?> type : PackagingElementFactory.getInstance().getNonCompositeElementTypes()) {
323 group.add(new AddNewPackagingElementAction(type, this));
325 return group;
328 public JComponent getMainComponent() {
329 return myMainPanel;
332 public void addNewPackagingElement(@NotNull PackagingElementType<?> type) {
333 myLayoutTreeComponent.addNewPackagingElement(type);
334 mySourceItemsTree.rebuildTree();
337 public void removeSelectedElements() {
338 myLayoutTreeComponent.removeSelectedElements();
341 public boolean isModified() {
342 return myBuildOnMakeCheckBox.isSelected() != myOriginalArtifact.isBuildOnMake()
343 || !Comparing.equal(getConfiguredOutputPath(), myOriginalArtifact.getOutputPath())
344 || myPropertiesEditors.isModified()
345 || myLayoutTreeComponent.isPropertiesModified();
348 public void dispose() {
351 public LayoutTreeComponent getLayoutTreeComponent() {
352 return myLayoutTreeComponent;
355 public void updateOutputPath(@NotNull String oldArtifactName, @NotNull final String newArtifactName) {
356 final String oldDefaultPath = ArtifactUtil.getDefaultArtifactOutputPath(oldArtifactName, myProject);
357 if (Comparing.equal(oldDefaultPath, getConfiguredOutputPath())) {
358 setOutputPath(ArtifactUtil.getDefaultArtifactOutputPath(newArtifactName, myProject));
359 final CompositePackagingElement<?> root = getRootElement();
360 if (root instanceof ArchivePackagingElement) {
361 String oldFileName = FileUtil.sanitizeFileName(oldArtifactName);
362 final String name = ((ArchivePackagingElement)root).getArchiveFileName();
363 final String fileName = FileUtil.getNameWithoutExtension(name);
364 final String extension = FileUtil.getExtension(name);
365 if (fileName.equals(oldFileName) && extension.length() > 0) {
366 myLayoutTreeComponent.editLayout(new Runnable() {
367 public void run() {
368 ((ArchivePackagingElement)getRootElement()).setArchiveFileName(FileUtil.sanitizeFileName(newArtifactName) + "." + extension);
371 myLayoutTreeComponent.updateRootNode();
377 public void updateLayoutTree() {
378 myLayoutTreeComponent.rebuildTree();
381 public void putLibraryIntoDefaultLocation(@NotNull Library library) {
382 myLayoutTreeComponent.putIntoDefaultLocations(Collections.singletonList(new LibrarySourceItem(library)));
385 public void putModuleIntoDefaultLocation(@NotNull Module module) {
386 myLayoutTreeComponent.putIntoDefaultLocations(Collections.singletonList(new ModuleOutputSourceItem(module)));
389 public void addToClasspath(final CompositePackagingElement<?> element, List<String> classpath) {
390 myLayoutTreeComponent.saveElementProperties();
391 ManifestFileConfiguration manifest = myContext.getManifestFile(element, getArtifact().getArtifactType());
392 if (manifest == null) {
393 final VirtualFile file = ManifestFileUtil.showDialogAndCreateManifest(myContext, element);
394 if (file == null) {
395 return;
398 ManifestFileUtil.addManifestFileToLayout(file.getPath(), myContext, element);
399 manifest = myContext.getManifestFile(element, getArtifact().getArtifactType());
402 if (manifest != null) {
403 manifest.addToClasspath(classpath);
405 myLayoutTreeComponent.resetElementProperties();
408 public void setArtifactType(ArtifactType artifactType) {
409 final ModifiableArtifact modifiableArtifact = myContext.getOrCreateModifiableArtifactModel().getOrCreateModifiableArtifact(myOriginalArtifact);
410 modifiableArtifact.setArtifactType(artifactType);
412 myPropertiesEditors.removeTabs(myTabbedPane);
413 myPropertiesEditors = new ArtifactPropertiesEditors(myContext, myOriginalArtifact, getArtifact());
414 myPropertiesEditors.addTabs(myTabbedPane);
416 final CompositePackagingElement<?> oldRootElement = getRootElement();
417 final CompositePackagingElement<?> newRootElement = artifactType.createRootElement(getArtifact().getName());
418 ArtifactUtil.copyChildren(oldRootElement, newRootElement, myProject);
419 myLayoutTreeComponent.setRootElement(newRootElement);
422 public ArtifactValidationManagerImpl getValidationManager() {
423 return myValidationManager;
426 private class MyDataProvider implements TypeSafeDataProvider {
427 public void calcData(DataKey key, DataSink sink) {
428 if (ARTIFACTS_EDITOR_KEY.equals(key)) {
429 sink.put(ARTIFACTS_EDITOR_KEY, ArtifactEditorImpl.this);