update copyright
[fedora-idea.git] / plugins / ui-designer / src / com / intellij / uiDesigner / designSurface / ListenerNavigateButton.java
blob91e1223c51181e710157044f1324a1022a38d568
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.
17 package com.intellij.uiDesigner.designSurface;
19 import com.intellij.ide.DataManager;
20 import com.intellij.openapi.actionSystem.AnAction;
21 import com.intellij.openapi.actionSystem.AnActionEvent;
22 import com.intellij.openapi.actionSystem.DataContext;
23 import com.intellij.openapi.actionSystem.DefaultActionGroup;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.ui.popup.JBPopupFactory;
26 import com.intellij.openapi.ui.popup.ListPopup;
27 import com.intellij.openapi.util.Comparing;
28 import com.intellij.openapi.util.IconLoader;
29 import com.intellij.pom.Navigatable;
30 import com.intellij.psi.*;
31 import com.intellij.psi.controlFlow.DefUseUtil;
32 import com.intellij.psi.presentation.java.ClassPresentationUtil;
33 import com.intellij.psi.search.LocalSearchScope;
34 import com.intellij.psi.search.searches.ReferencesSearch;
35 import com.intellij.psi.util.PsiTreeUtil;
36 import com.intellij.uiDesigner.FormEditingUtil;
37 import com.intellij.uiDesigner.UIDesignerBundle;
38 import com.intellij.uiDesigner.lw.IRootContainer;
39 import com.intellij.uiDesigner.radComponents.RadComponent;
40 import com.intellij.util.Processor;
41 import org.jetbrains.annotations.Nullable;
43 import javax.swing.*;
44 import java.awt.*;
45 import java.awt.event.ActionEvent;
46 import java.awt.event.ActionListener;
47 import java.beans.BeanInfo;
48 import java.beans.EventSetDescriptor;
49 import java.beans.IntrospectionException;
50 import java.beans.Introspector;
52 /**
53 * @author yole
55 public class ListenerNavigateButton extends JButton implements ActionListener {
56 private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.designSurface.ListenerNavigateButton");
58 private final RadComponent myComponent;
60 public ListenerNavigateButton(RadComponent component) {
61 myComponent = component;
62 setIcon(IconLoader.getIcon("/com/intellij/uiDesigner/icons/listener.png"));
63 setOpaque(false);
64 setFocusable(false);
65 setBorderPainted(false);
66 setSize(new Dimension(getIcon().getIconWidth(), getIcon().getIconHeight()));
67 addActionListener(this);
70 public void actionPerformed(ActionEvent e) {
71 showNavigatePopup(myComponent, false);
74 public static void showNavigatePopup(final RadComponent component, final boolean showIfEmpty) {
75 final DefaultActionGroup actionGroup = prepareActionGroup(component);
76 if (actionGroup != null && actionGroup.getChildrenCount() == 0 && showIfEmpty) {
77 actionGroup.add(new MyNavigateAction(UIDesignerBundle.message("navigate.to.listener.empty"), null));
79 if (actionGroup != null && actionGroup.getChildrenCount() > 0) {
80 final DataContext context = DataManager.getInstance().getDataContext(component.getDelegee());
81 final JBPopupFactory factory = JBPopupFactory.getInstance();
82 final ListPopup popup = factory.createActionGroupPopup(UIDesignerBundle.message("navigate.to.listener.title"), actionGroup, context,
83 JBPopupFactory.ActionSelectionAid.NUMBERING, true);
84 FormEditingUtil.showPopupUnderComponent(popup, component);
88 @Nullable
89 public static DefaultActionGroup prepareActionGroup(final RadComponent component) {
90 final IRootContainer root = FormEditingUtil.getRoot(component);
91 final String classToBind = root == null ? null : root.getClassToBind();
92 if (classToBind != null) {
93 final PsiClass aClass = FormEditingUtil.findClassToBind(component.getModule(), classToBind);
94 if (aClass != null) {
95 final PsiField boundField = aClass.findFieldByName(component.getBinding(), false);
96 if (boundField != null) {
97 return buildNavigateActionGroup(component, boundField);
101 return null;
104 private static DefaultActionGroup buildNavigateActionGroup(RadComponent component, final PsiField boundField) {
105 final DefaultActionGroup actionGroup = new DefaultActionGroup();
106 final EventSetDescriptor[] eventSetDescriptors;
107 try {
108 BeanInfo beanInfo = Introspector.getBeanInfo(component.getComponentClass());
109 eventSetDescriptors = beanInfo.getEventSetDescriptors();
111 catch (IntrospectionException e) {
112 LOG.error(e);
113 return null;
115 final LocalSearchScope scope = new LocalSearchScope(boundField.getContainingFile());
116 ReferencesSearch.search(boundField, scope).forEach(new Processor<PsiReference>() {
117 public boolean process(final PsiReference ref) {
118 final PsiElement element = ref.getElement();
119 if (element.getParent() instanceof PsiReferenceExpression) {
120 PsiReferenceExpression refExpr = (PsiReferenceExpression) element.getParent();
121 if (refExpr.getParent() instanceof PsiMethodCallExpression) {
122 PsiMethodCallExpression methodCall = (PsiMethodCallExpression) refExpr.getParent();
123 final PsiElement psiElement = refExpr.resolve();
124 if (psiElement instanceof PsiMethod) {
125 PsiMethod method = (PsiMethod) psiElement;
126 for(EventSetDescriptor eventSetDescriptor: eventSetDescriptors) {
127 if (Comparing.equal(eventSetDescriptor.getAddListenerMethod().getName(), method.getName())) {
128 final String eventName = eventSetDescriptor.getName();
129 final PsiExpression[] args = methodCall.getArgumentList().getExpressions();
130 if (args.length > 0) {
131 addListenerRef(actionGroup, eventName, args[0]);
138 return true;
142 return actionGroup;
145 private static void addListenerRef(final DefaultActionGroup actionGroup, final String eventName, final PsiExpression listenerArg) {
146 final PsiType type = listenerArg.getType();
147 if (type instanceof PsiClassType) {
148 PsiClass listenerClass = ((PsiClassType) type).resolve();
149 if (listenerClass != null) {
150 if (!isAbstractOrInterface(listenerClass)) {
151 actionGroup.add(new MyNavigateAction(eventName + ": " + ClassPresentationUtil.getNameForClass(listenerClass, false),
152 listenerClass));
153 return;
155 else if (listenerArg instanceof PsiReferenceExpression) {
156 final PsiElement psiElement = ((PsiReferenceExpression)listenerArg).resolve();
157 if (psiElement instanceof PsiVariable) {
158 PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(listenerArg, PsiCodeBlock.class);
159 final PsiElement[] defs = DefUseUtil.getDefs(codeBlock, (PsiVariable)psiElement, listenerArg);
160 if (defs.length == 1) {
161 final PsiElement def = defs[0];
162 if (def instanceof PsiVariable) {
163 PsiVariable var = (PsiVariable) def;
164 if (var.getInitializer() != listenerArg) {
165 addListenerRef(actionGroup, eventName, var.getInitializer());
166 return;
169 else if (def.getParent() instanceof PsiAssignmentExpression) {
170 final PsiAssignmentExpression assignmentExpr = (PsiAssignmentExpression)def.getParent();
171 if (def.equals(assignmentExpr.getLExpression())) {
172 addListenerRef(actionGroup, eventName, assignmentExpr.getRExpression());
173 return;
181 actionGroup.add(new MyNavigateAction(eventName + ": " + listenerArg.getText(), listenerArg));
184 private static boolean isAbstractOrInterface(final PsiClass element) {
185 return element.isInterface() ||
186 element.hasModifierProperty(PsiModifier.ABSTRACT);
189 private static class MyNavigateAction extends AnAction {
190 private final PsiElement myElement;
192 public MyNavigateAction(final String name, PsiElement element) {
193 super(name);
194 myElement = element;
197 public void actionPerformed(AnActionEvent e) {
198 if (myElement instanceof Navigatable) {
199 ((Navigatable) myElement).navigate(true);
203 @Override public void update(AnActionEvent e) {
204 e.getPresentation().setEnabled(myElement != null &&
205 (!(myElement instanceof PsiClass) || !isAbstractOrInterface((PsiClass)myElement)));