Ant: standard look of the toolwindow
[fedora-idea.git] / plugins / ant / src / com / intellij / lang / ant / config / explorer / AntExplorer.java
blobd10db02ed7f6623d2dbbee625469debf7c82485d
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.lang.ant.config.explorer;
18 import com.intellij.ide.CommonActionsManager;
19 import com.intellij.ide.DataManager;
20 import com.intellij.ide.TreeExpander;
21 import com.intellij.ide.actions.ContextHelpAction;
22 import com.intellij.lang.ant.AntBundle;
23 import com.intellij.lang.ant.config.*;
24 import com.intellij.lang.ant.config.actions.AntBuildFilePropertiesAction;
25 import com.intellij.lang.ant.config.actions.RemoveBuildFileAction;
26 import com.intellij.lang.ant.config.execution.ExecutionHandler;
27 import com.intellij.lang.ant.config.impl.*;
28 import com.intellij.lang.ant.config.impl.configuration.BuildFilePropertiesPanel;
29 import com.intellij.openapi.Disposable;
30 import com.intellij.openapi.actionSystem.*;
31 import com.intellij.openapi.application.ApplicationManager;
32 import com.intellij.openapi.diagnostic.Logger;
33 import com.intellij.openapi.fileChooser.FileChooser;
34 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
35 import com.intellij.openapi.fileEditor.OpenFileDescriptor;
36 import com.intellij.openapi.fileTypes.FileTypeManager;
37 import com.intellij.openapi.fileTypes.StdFileTypes;
38 import com.intellij.openapi.keymap.Keymap;
39 import com.intellij.openapi.keymap.KeymapManagerListener;
40 import com.intellij.openapi.keymap.ex.KeymapManagerEx;
41 import com.intellij.openapi.keymap.impl.ui.EditKeymapsDialog;
42 import com.intellij.openapi.project.Project;
43 import com.intellij.openapi.ui.Messages;
44 import com.intellij.openapi.ui.SimpleToolWindowPanel;
45 import com.intellij.openapi.util.Disposer;
46 import com.intellij.openapi.util.IconLoader;
47 import com.intellij.openapi.vfs.VfsUtil;
48 import com.intellij.openapi.vfs.VirtualFile;
49 import com.intellij.ui.*;
50 import com.intellij.ui.treeStructure.Tree;
51 import com.intellij.util.ArrayUtil;
52 import com.intellij.util.StringBuilderSpinAllocator;
53 import com.intellij.util.ui.tree.TreeUtil;
54 import org.jetbrains.annotations.NonNls;
55 import org.jetbrains.annotations.Nullable;
57 import javax.swing.*;
58 import javax.swing.tree.DefaultMutableTreeNode;
59 import javax.swing.tree.DefaultTreeModel;
60 import javax.swing.tree.TreePath;
61 import java.awt.*;
62 import java.awt.event.ActionEvent;
63 import java.awt.event.KeyEvent;
64 import java.awt.event.MouseAdapter;
65 import java.awt.event.MouseEvent;
66 import java.util.ArrayList;
67 import java.util.Arrays;
68 import java.util.List;
70 public class AntExplorer extends SimpleToolWindowPanel implements DataProvider {
72 private static final Logger LOG = Logger.getInstance("#com.intellij.lang.ant.config.explorer.AntExplorer");
74 private Project myProject;
75 private AntExplorerTreeBuilder myBuilder;
76 private Tree myTree;
77 private KeymapListener myKeymapListener;
78 private final List<Disposable> myDisposables = new ArrayList<Disposable>();
79 private final AntBuildFilePropertiesAction myAntBuildFilePropertiesAction;
81 private final TreeExpander myTreeExpander = new TreeExpander() {
82 public void expandAll() {
83 myBuilder.expandAll();
86 public boolean canExpand() {
87 return AntConfiguration.getInstance(myProject).getBuildFiles().length != 0;
90 public void collapseAll() {
91 myBuilder.collapseAll();
94 public boolean canCollapse() {
95 return canExpand();
98 private static final Icon ICON_RUN = IconLoader.getIcon("/actions/execute.png");
99 private static final Icon ICON_REMOVE = IconLoader.getIcon("/general/remove.png");
100 private static final Icon ICON_ADD = IconLoader.getIcon("/general/add.png");
101 private static final Icon ICON_FILTER = IconLoader.getIcon("/ant/filter.png");
103 public AntExplorer(final Project project) {
104 super(true, true);
105 myProject = project;
106 final DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode());
107 myTree = new Tree(model);
108 myTree.setRootVisible(false);
109 myTree.setShowsRootHandles(true);
110 myTree.setCellRenderer(new NodeRenderer());
111 myBuilder = new AntExplorerTreeBuilder(project, myTree, model);
112 myBuilder.setTargetsFiltered(AntConfigurationBase.getInstance(project).isFilterTargets());
113 TreeToolTipHandler.install(myTree);
114 TreeUtil.installActions(myTree);
115 new TreeSpeedSearch(myTree);
116 myTree.addMouseListener(new PopupHandler() {
117 public void invokePopup(final Component comp, final int x, final int y) {
118 popupInvoked(comp, x, y);
121 myTree.addMouseListener(new MouseAdapter() {
122 public void mouseClicked(MouseEvent e) {
123 if (e.getClickCount() == 2) {
124 final TreePath path = myTree.getPathForLocation(e.getX(), e.getY());
125 if (path != null) {
126 runSelection(DataManager.getInstance().getDataContext(myTree));
131 myTree.registerKeyboardAction(new AbstractAction() {
132 public void actionPerformed(ActionEvent e) {
133 runSelection(DataManager.getInstance().getDataContext(myTree));
135 }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), WHEN_FOCUSED);
136 myTree.expandRow(0);
137 myTree.setLineStyleAngled();
138 myAntBuildFilePropertiesAction = new AntBuildFilePropertiesAction(this);
139 setToolbar(createToolbarPanel());
140 setContent(new JScrollPane(myTree));
141 ToolTipManager.sharedInstance().registerComponent(myTree);
142 myKeymapListener = new KeymapListener();
145 public void dispose() {
146 for (final Disposable disposable : myDisposables) {
147 disposable.dispose();
149 myDisposables.clear();
150 myProject = null;
151 if (myKeymapListener != null) {
152 myKeymapListener.stopListen();
153 myKeymapListener = null;
155 else {
156 LOG.error("already disposed");
158 if (myBuilder != null) {
159 Disposer.dispose(myBuilder);
161 myBuilder = null;
162 if (myTree != null) {
163 ToolTipManager.sharedInstance().unregisterComponent(myTree);
164 final KeyStroke[] strokes = myTree.getRegisteredKeyStrokes();
165 for (KeyStroke keyStroke : strokes) {
166 myTree.unregisterKeyboardAction(keyStroke);
168 myTree = null;
172 private JPanel createToolbarPanel() {
173 final DefaultActionGroup group = new DefaultActionGroup();
174 group.add(new AddAction());
175 group.add(new RemoveAction());
176 group.add(new RunAction());
177 group.add(new ShowAllTargetsAction());
178 AnAction action = CommonActionsManager.getInstance().createExpandAllAction(myTreeExpander, this);
179 action.getTemplatePresentation().setDescription(AntBundle.message("ant.explorer.expand.all.nodes.action.description"));
180 group.add(action);
181 action = CommonActionsManager.getInstance().createCollapseAllAction(myTreeExpander, this);
182 action.getTemplatePresentation().setDescription(AntBundle.message("ant.explorer.collapse.all.nodes.action.description"));
183 group.add(action);
184 group.add(myAntBuildFilePropertiesAction);
185 group.add(new ContextHelpAction(HelpID.ANT));
187 final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar(ActionPlaces.ANT_EXPLORER_TOOLBAR, group, true);
188 final JPanel buttonsPanel = new JPanel(new BorderLayout());
189 buttonsPanel.add(actionToolBar.getComponent(), BorderLayout.CENTER);
190 return buttonsPanel;
193 private void addBuildFile() {
194 final FileChooserDescriptor descriptor = createXmlDescriptor();
195 descriptor.setTitle(AntBundle.message("select.ant.build.file.dialog.title"));
196 descriptor.setDescription(AntBundle.message("select.ant.build.file.dialog.description"));
197 final VirtualFile[] files = FileChooser.chooseFiles(myProject, descriptor);
198 if (files.length == 0) {
199 return;
201 ApplicationManager.getApplication().invokeLater(new Runnable() {
202 public void run() {
203 final AntConfiguration antConfiguration = AntConfiguration.getInstance(myProject);
204 final ArrayList<VirtualFile> ignoredFiles = new ArrayList<VirtualFile>();
205 for (VirtualFile file : files) {
206 try {
207 antConfiguration.addBuildFile(file);
209 catch (AntNoFileException e) {
210 ignoredFiles.add(e.getFile());
213 if (ignoredFiles.size() != 0) {
214 String messageText;
215 final StringBuilder message = StringBuilderSpinAllocator.alloc();
216 try {
217 String separator = "";
218 for (final VirtualFile virtualFile : ignoredFiles) {
219 message.append(separator);
220 message.append(virtualFile.getPresentableUrl());
221 separator = "\n";
223 messageText = message.toString();
225 finally {
226 StringBuilderSpinAllocator.dispose(message);
228 Messages.showWarningDialog(myProject, messageText, AntBundle.message("cannot.add.ant.files.dialog.title"));
234 public void removeBuildFile() {
235 final AntBuildFile buildFile = getCurrentBuildFile();
236 if (buildFile == null) {
237 return;
239 final String fileName = buildFile.getPresentableUrl();
240 final int result = Messages.showYesNoDialog(myProject, AntBundle.message("remove.the.reference.to.file.confirmation.text", fileName),
241 AntBundle.message("confirm.remove.dialog.title"), Messages.getQuestionIcon());
242 if (result != 0) {
243 return;
245 AntConfiguration.getInstance(myProject).removeBuildFile(buildFile);
248 public void setBuildFileProperties(DataContext dataContext) {
249 final AntBuildFile buildFile = getCurrentBuildFile();
250 if (BuildFilePropertiesPanel.editBuildFile(getCurrentBuildFile())) {
251 final AntConfiguration antConfiguration = AntConfiguration.getInstance(myProject);
252 antConfiguration.updateBuildFile(buildFile);
253 myBuilder.refresh();
254 myTree.repaint();
258 private void runSelection(final DataContext dataContext) {
259 if (!canRunSelection()) {
260 return;
262 final AntBuildFileBase buildFile = getCurrentBuildFile();
263 final TreePath[] paths = myTree.getSelectionPaths();
264 final String[] targets = getTargetNamesFromPaths(paths);
265 ExecutionHandler.runBuild(buildFile, targets, null, dataContext, AntBuildListener.NULL);
268 private boolean canRunSelection() {
269 if (myTree == null) {
270 return false;
272 final TreePath[] paths = myTree.getSelectionPaths();
273 if (paths == null) {
274 return false;
276 final AntBuildFile buildFile = getCurrentBuildFile();
277 if (buildFile == null || !buildFile.exists()) {
278 return false;
280 for (final TreePath path : paths) {
281 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
282 final Object userObject = node.getUserObject();
283 final AntBuildFileNodeDescriptor buildFileNodeDescriptor;
284 if (userObject instanceof AntTargetNodeDescriptor) {
285 buildFileNodeDescriptor = (AntBuildFileNodeDescriptor)((DefaultMutableTreeNode)node.getParent()).getUserObject();
287 else if (userObject instanceof AntBuildFileNodeDescriptor){
288 buildFileNodeDescriptor = (AntBuildFileNodeDescriptor)userObject;
290 else {
291 buildFileNodeDescriptor = null;
293 if (buildFileNodeDescriptor == null || buildFileNodeDescriptor.getBuildFile() != buildFile) {
294 return false;
297 return true;
300 private static String[] getTargetNamesFromPaths(TreePath[] paths) {
301 final List<String> targets = new ArrayList<String>();
302 for (final TreePath path : paths) {
303 final Object userObject = ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
304 if (!(userObject instanceof AntTargetNodeDescriptor)) {
305 continue;
307 final AntBuildTarget target = ((AntTargetNodeDescriptor)userObject).getTarget();
308 if (target instanceof MetaTarget) {
309 targets.addAll(Arrays.asList(((MetaTarget)target).getTargetNames()));
311 else {
312 targets.add(target.getName());
315 return ArrayUtil.toStringArray(targets);
318 private static AntBuildTarget[] getTargetObjectsFromPaths(TreePath[] paths) {
319 final List<AntBuildTargetBase> targets = new ArrayList<AntBuildTargetBase>();
320 for (final TreePath path : paths) {
321 final Object userObject = ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
322 if (!(userObject instanceof AntTargetNodeDescriptor)) {
323 continue;
325 final AntBuildTargetBase target = ((AntTargetNodeDescriptor)userObject).getTarget();
326 targets.add(target);
329 return targets.toArray(new AntBuildTargetBase[targets.size()]);
332 public boolean isBuildFileSelected() {
333 if( myProject == null) return false;
334 final AntBuildFileBase file = getCurrentBuildFile();
335 return file != null && file.exists();
338 @Nullable
339 private AntBuildFileBase getCurrentBuildFile() {
340 final AntBuildFileNodeDescriptor descriptor = getCurrentBuildFileNodeDescriptor();
341 return (AntBuildFileBase)((descriptor == null) ? null : descriptor.getBuildFile());
344 @Nullable
345 private AntBuildFileNodeDescriptor getCurrentBuildFileNodeDescriptor() {
346 if (myTree == null) {
347 return null;
349 final TreePath path = myTree.getSelectionPath();
350 if (path == null) {
351 return null;
353 DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
354 while (node != null) {
355 final Object userObject = node.getUserObject();
356 if (userObject instanceof AntBuildFileNodeDescriptor) {
357 return (AntBuildFileNodeDescriptor)userObject;
359 node = (DefaultMutableTreeNode)node.getParent();
361 return null;
364 private void popupInvoked(final Component comp, final int x, final int y) {
365 Object userObject = null;
366 final TreePath path = myTree.getSelectionPath();
367 if (path != null) {
368 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
369 if (node != null) {
370 userObject = node.getUserObject();
373 final DefaultActionGroup group = new DefaultActionGroup();
374 group.add(new RunAction());
375 group.add(new CreateMetaTargetAction());
376 group.add(new RemoveMetaTargetsOrBuildFileAction());
377 group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_EDIT_SOURCE));
378 if (userObject instanceof AntBuildFileNodeDescriptor) {
379 group.add(new RemoveBuildFileAction(this));
381 if (userObject instanceof AntTargetNodeDescriptor) {
382 final AntBuildTargetBase target = ((AntTargetNodeDescriptor)userObject).getTarget();
383 final DefaultActionGroup executeOnGroup =
384 new DefaultActionGroup(AntBundle.message("ant.explorer.execute.on.action.group.name"), true);
385 executeOnGroup.add(new ExecuteOnEventAction(target, ExecuteBeforeCompilationEvent.getInstance()));
386 executeOnGroup.add(new ExecuteOnEventAction(target, ExecuteAfterCompilationEvent.getInstance()));
387 executeOnGroup.addSeparator();
388 executeOnGroup.add(new ExecuteBeforeRunAction(target, getCurrentBuildFile()));
389 group.add(executeOnGroup);
390 group.add(new AssignShortcutAction(target.getActionId()));
392 group.add(myAntBuildFilePropertiesAction);
393 final ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.ANT_EXPLORER_POPUP, group);
394 popupMenu.getComponent().show(comp, x, y);
397 @Nullable
398 public Object getData(@NonNls String dataId) {
399 if (PlatformDataKeys.NAVIGATABLE.is(dataId)) {
400 final AntBuildFile buildFile = getCurrentBuildFile();
401 if (buildFile == null) {
402 return null;
404 final VirtualFile file = buildFile.getVirtualFile();
405 if (file == null) {
406 return null;
408 final TreePath treePath = myTree.getLeadSelectionPath();
409 if (treePath == null) {
410 return null;
412 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent();
413 if (node == null) {
414 return null;
416 if (node.getUserObject() instanceof AntTargetNodeDescriptor) {
417 final AntTargetNodeDescriptor targetNodeDescriptor = (AntTargetNodeDescriptor)node.getUserObject();
418 final AntBuildTargetBase buildTarget = targetNodeDescriptor.getTarget();
419 final OpenFileDescriptor descriptor = buildTarget.getOpenFileDescriptor();
420 if (descriptor != null) {
421 final VirtualFile descriptorFile = descriptor.getFile();
422 if (descriptorFile.isValid()) {
423 return descriptor;
427 if (file.isValid()) {
428 return new OpenFileDescriptor(myProject, file);
431 else if (PlatformDataKeys.HELP_ID.is(dataId)) {
432 return HelpID.ANT;
434 else if (PlatformDataKeys.TREE_EXPANDER.is(dataId)) {
435 return myTreeExpander;
437 else if (PlatformDataKeys.VIRTUAL_FILE_ARRAY.is(dataId)) {
438 final TreePath[] paths = myTree.getSelectionPaths();
439 if (paths == null) {
440 return null;
442 final ArrayList<VirtualFile> result = new ArrayList<VirtualFile>();
443 for (final TreePath path : paths) {
444 for (DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
445 node != null;
446 node = (DefaultMutableTreeNode)node.getParent()) {
447 final Object userObject = node.getUserObject();
448 if (!(userObject instanceof AntBuildFileNodeDescriptor)) {
449 continue;
451 final AntBuildFile buildFile = ((AntBuildFileNodeDescriptor)userObject).getBuildFile();
452 if (buildFile != null) {
453 final VirtualFile virtualFile = buildFile.getVirtualFile();
454 if (virtualFile != null && virtualFile.isValid()) {
455 result.add(virtualFile);
458 break;
461 if (result.size() == 0) {
462 return null;
464 return VfsUtil.toVirtualFileArray(result);
466 return null;
469 public static FileChooserDescriptor createXmlDescriptor() {
470 return new FileChooserDescriptor(true, false, false, false, false, true){
471 public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
472 boolean b = super.isFileVisible(file, showHiddenFiles);
473 if (!file.isDirectory()) {
474 b &= StdFileTypes.XML.equals(FileTypeManager.getInstance().getFileTypeByFile(file));
476 return b;
481 private static final class NodeRenderer extends ColoredTreeCellRenderer {
482 public void customizeCellRenderer(JTree tree,
483 Object value,
484 boolean selected,
485 boolean expanded,
486 boolean leaf,
487 int row,
488 boolean hasFocus) {
489 final Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
490 if (userObject instanceof AntNodeDescriptor) {
491 final AntNodeDescriptor descriptor = (AntNodeDescriptor)userObject;
492 descriptor.customize(this);
494 else {
495 append(tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus), SimpleTextAttributes.REGULAR_ATTRIBUTES);
500 private final class AddAction extends AnAction {
501 public AddAction() {
502 super(AntBundle.message("add.ant.file.action.name"), AntBundle.message("add.ant.file.action.description"), ICON_ADD);
505 public void actionPerformed(AnActionEvent e) {
506 addBuildFile();
510 private final class RemoveAction extends AnAction {
511 public RemoveAction() {
512 super(AntBundle.message("remove.ant.file.action.name"), AntBundle.message("remove.ant.file.action.description"), ICON_REMOVE);
515 public void actionPerformed(AnActionEvent e) {
516 removeBuildFile();
519 public void update(AnActionEvent event) {
520 event.getPresentation().setEnabled(getCurrentBuildFile() != null);
524 private final class RunAction extends AnAction {
525 public RunAction() {
526 super(AntBundle.message("run.ant.file.or.target.action.name"), AntBundle.message("run.ant.file.or.target.action.description"), ICON_RUN);
529 public void actionPerformed(AnActionEvent e) {
530 runSelection(e.getDataContext());
533 public void update(AnActionEvent event) {
534 final Presentation presentation = event.getPresentation();
535 final String place = event.getPlace();
536 if (ActionPlaces.ANT_EXPLORER_TOOLBAR.equals(place)) {
537 presentation.setText(AntBundle.message("run.ant.file.or.target.action.name"));
539 else {
540 final TreePath[] paths = myTree.getSelectionPaths();
541 if (paths != null && paths.length == 1 &&
542 ((DefaultMutableTreeNode)paths[0].getLastPathComponent()).getUserObject() instanceof AntBuildFileNodeDescriptor) {
543 presentation.setText(AntBundle.message("run.ant.build.action.name"));
545 else {
546 if (paths == null || paths.length == 1) {
547 presentation.setText(AntBundle.message("run.ant.target.action.name"));
549 else {
550 presentation.setText(AntBundle.message("run.ant.targets.action.name"));
555 presentation.setEnabled(canRunSelection());
559 private final class ShowAllTargetsAction extends ToggleAction {
560 public ShowAllTargetsAction() {
561 super(AntBundle.message("filter.ant.targets.action.name"), AntBundle.message("filter.ant.targets.action.description"), ICON_FILTER);
564 public boolean isSelected(AnActionEvent event) {
565 final Project project = myProject;
566 return project != null? AntConfigurationBase.getInstance(project).isFilterTargets() : false;
569 public void setSelected(AnActionEvent event, boolean flag) {
570 setTargetsFiltered(flag);
574 private void setTargetsFiltered(boolean value) {
575 myBuilder.setTargetsFiltered(value);
576 AntConfigurationBase.getInstance(myProject).setFilterTargets(value);
579 private final class ExecuteOnEventAction extends ToggleAction {
580 private final AntBuildTargetBase myTarget;
581 private final ExecutionEvent myExecutionEvent;
583 public ExecuteOnEventAction(final AntBuildTargetBase target, final ExecutionEvent executionEvent) {
584 super(executionEvent.getPresentableName());
585 myTarget = target;
586 myExecutionEvent = executionEvent;
589 public boolean isSelected(AnActionEvent e) {
590 return myTarget.equals(AntConfigurationBase.getInstance(myProject).getTargetForEvent(myExecutionEvent));
593 public void setSelected(AnActionEvent event, boolean state) {
594 final AntConfigurationBase antConfiguration = AntConfigurationBase.getInstance(myProject);
595 if (state) {
596 final AntBuildFileBase buildFile =
597 (AntBuildFileBase)((myTarget instanceof MetaTarget) ? ((MetaTarget)myTarget).getBuildFile() : myTarget.getModel().getBuildFile());
598 antConfiguration.setTargetForEvent(buildFile, myTarget.getName(), myExecutionEvent);
600 else {
601 antConfiguration.clearTargetForEvent(myExecutionEvent);
603 myBuilder.refresh();
606 public void update(AnActionEvent e) {
607 super.update(e);
608 final AntBuildFile buildFile = myTarget.getModel().getBuildFile();
609 e.getPresentation().setEnabled(buildFile != null && buildFile.exists());
613 private final class ExecuteBeforeRunAction extends AnAction {
614 private final AntBuildTarget myTarget;
615 private final AntBuildFile myBuildFile;
617 public ExecuteBeforeRunAction(final AntBuildTarget target, final AntBuildFile buildFile) {
618 super(AntBundle.message("executes.before.run.debug.acton.name"));
619 myTarget = target;
620 myBuildFile = buildFile;
623 public void actionPerformed(AnActionEvent e) {
624 final ExecuteOnRunDialog dialog = new ExecuteOnRunDialog(myProject, myTarget, myBuildFile);
625 dialog.show();
626 myBuilder.refresh();
629 public void update(AnActionEvent e) {
630 e.getPresentation().setEnabled(myBuildFile.exists());
634 private final class CreateMetaTargetAction extends AnAction {
636 public CreateMetaTargetAction() {
637 super(AntBundle.message("ant.create.meta.target.action.name"), AntBundle.message("ant.create.meta.target.action.description"), null
638 /*IconLoader.getIcon("/actions/execute.png")*/);
641 public void actionPerformed(AnActionEvent e) {
642 final AntBuildFile buildFile = getCurrentBuildFile();
643 final String[] targets = getTargetNamesFromPaths(myTree.getSelectionPaths());
644 final ExecuteCompositeTargetEvent event = new ExecuteCompositeTargetEvent(targets);
645 final SaveMetaTargetDialog dialog = new SaveMetaTargetDialog(myTree, event, AntConfigurationBase.getInstance(myProject), buildFile);
646 dialog.setTitle(e.getPresentation().getText());
647 dialog.show();
648 if (dialog.isOK()) {
649 myBuilder.refresh();
650 myTree.repaint();
654 public void update(AnActionEvent e) {
655 final TreePath[] paths = myTree.getSelectionPaths();
656 e.getPresentation().setEnabled(paths != null && paths.length > 1 && canRunSelection());
660 private final class RemoveMetaTargetsOrBuildFileAction extends AnAction {
662 public RemoveMetaTargetsOrBuildFileAction() {
663 super(AntBundle.message("remove.meta.targets.action.name"), AntBundle.message("remove.meta.targets.action.description"), null);
664 registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)), myTree);
665 myDisposables.add(new Disposable() {
666 public void dispose() {
667 RemoveMetaTargetsOrBuildFileAction.this.unregisterCustomShortcutSet(myTree);
670 myTree.registerKeyboardAction(new AbstractAction() {
671 public void actionPerformed(ActionEvent e) {
672 doAction();
674 }, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
677 public void actionPerformed(AnActionEvent e) {
678 doAction();
681 private void doAction() {
682 final TreePath[] paths = myTree.getSelectionPaths();
683 if (paths == null) {
684 return;
686 try {
687 // try to remove build file
688 if (paths.length == 1) {
689 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[0].getLastPathComponent();
690 if (node.getUserObject() instanceof AntBuildFileNodeDescriptor) {
691 final AntBuildFileNodeDescriptor descriptor = (AntBuildFileNodeDescriptor)node.getUserObject();
692 if (descriptor.getBuildFile().equals(getCurrentBuildFile())) {
693 removeBuildFile();
694 return;
698 // try to remove meta targets
699 final AntBuildTarget[] targets = getTargetObjectsFromPaths(paths);
700 final AntConfigurationBase antConfiguration = AntConfigurationBase.getInstance(myProject);
701 for (final AntBuildTarget buildTarget : targets) {
702 if (buildTarget instanceof MetaTarget) {
703 for (final ExecutionEvent event : antConfiguration.getEventsForTarget(buildTarget)) {
704 if (event instanceof ExecuteCompositeTargetEvent) {
705 antConfiguration.clearTargetForEvent(event);
711 finally {
712 myBuilder.refresh();
713 myTree.repaint();
717 public void update(AnActionEvent e) {
718 final Presentation presentation = e.getPresentation();
719 final TreePath[] paths = myTree.getSelectionPaths();
720 if (paths == null) {
721 presentation.setEnabled(false);
722 return;
725 if (paths.length == 1) {
726 String text = AntBundle.message("remove.meta.target.action.name");
727 boolean enabled = false;
728 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[0].getLastPathComponent();
729 if (node.getUserObject() instanceof AntBuildFileNodeDescriptor) {
730 final AntBuildFileNodeDescriptor descriptor = (AntBuildFileNodeDescriptor)node.getUserObject();
731 if (descriptor.getBuildFile().equals(getCurrentBuildFile())) {
732 text = AntBundle.message("remove.selected.build.file.action.name");
733 enabled = true;
736 else {
737 if (node.getUserObject() instanceof AntTargetNodeDescriptor) {
738 final AntTargetNodeDescriptor descr = (AntTargetNodeDescriptor)node.getUserObject();
739 final AntBuildTargetBase target = descr.getTarget();
740 if (target instanceof MetaTarget) {
741 enabled = true;
745 presentation.setText(text);
746 presentation.setEnabled(enabled);
748 else {
749 presentation.setText(AntBundle.message("remove.selected.meta.targets.action.name"));
750 final AntBuildTarget[] targets = getTargetObjectsFromPaths(paths);
751 boolean enabled = targets.length > 0;
752 for (final AntBuildTarget buildTarget : targets) {
753 if (!(buildTarget instanceof MetaTarget)) {
754 enabled = false;
755 break;
758 presentation.setEnabled(enabled);
763 private final class AssignShortcutAction extends AnAction {
764 private final String myActionId;
766 public AssignShortcutAction(String actionId) {
767 super(AntBundle.message("ant.explorer.assign.shortcut.action.name"));
768 myActionId = actionId;
771 public void actionPerformed(AnActionEvent e) {
772 new EditKeymapsDialog(myProject, myActionId).show();
775 public void update(AnActionEvent e) {
776 e.getPresentation().setEnabled(myActionId != null && ActionManager.getInstance().getAction(myActionId) != null);
780 private class KeymapListener implements KeymapManagerListener, Keymap.Listener {
781 private Keymap myCurrentKeymap = null;
783 public KeymapListener() {
784 final KeymapManagerEx keymapManager = KeymapManagerEx.getInstanceEx();
785 final Keymap activeKeymap = keymapManager.getActiveKeymap();
786 listenTo(activeKeymap);
787 keymapManager.addKeymapManagerListener(this);
790 public void activeKeymapChanged(Keymap keymap) {
791 listenTo(keymap);
792 updateTree();
795 private void listenTo(Keymap keymap) {
796 if (myCurrentKeymap != null) {
797 myCurrentKeymap.removeShortcutChangeListener(this);
799 myCurrentKeymap = keymap;
800 if (myCurrentKeymap != null) {
801 myCurrentKeymap.addShortcutChangeListener(this);
805 private void updateTree() {
806 myBuilder.updateFromRoot();
809 public void onShortcutChanged(String actionId) {
810 updateTree();
813 public void stopListen() {
814 listenTo(null);
815 KeymapManagerEx.getInstanceEx().removeKeymapManagerListener(this);