- use editor font in implements/override popup
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / daemon / impl / PsiElementListNavigator.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.codeInsight.daemon.impl;
18
19 import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask;
20 import com.intellij.find.FindUtil;
21 import com.intellij.ide.PsiCopyPasteManager;
22 import com.intellij.ide.util.PsiElementListCellRenderer;
23 import com.intellij.ide.util.gotoByName.ChooseByNameBase;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.editor.Editor;
26 import com.intellij.openapi.progress.ProgressManager;
27 import com.intellij.openapi.ui.popup.JBPopup;
28 import com.intellij.openapi.ui.popup.PopupChooserBuilder;
29 import com.intellij.openapi.util.Computable;
30 import com.intellij.openapi.util.Ref;
31 import com.intellij.psi.NavigatablePsiElement;
32 import com.intellij.psi.PsiElement;
33 import com.intellij.ui.CollectionListModel;
34 import com.intellij.ui.JBListWithHintProvider;
35 import com.intellij.ui.awt.RelativePoint;
36 import com.intellij.ui.popup.AbstractPopup;
37 import com.intellij.ui.popup.HintUpdateSupply;
38 import com.intellij.usages.UsageView;
39 import com.intellij.util.Consumer;
40 import com.intellij.util.Processor;
41 import org.jetbrains.annotations.NotNull;
42 import org.jetbrains.annotations.Nullable;
43
44 import javax.swing.*;
45 import java.awt.datatransfer.Transferable;
46 import java.awt.event.MouseEvent;
47 import java.util.List;
48
49 public class PsiElementListNavigator {
50   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.PsiElementListNavigator");
51
52   private PsiElementListNavigator() {
53   }
54
55   public static void openTargets(MouseEvent e, NavigatablePsiElement[] targets, String title, final String findUsagesTitle, ListCellRenderer listRenderer) {
56     openTargets(e, targets, title, findUsagesTitle, listRenderer, null);
57   }
58
59   public static void openTargets(MouseEvent e,
60                                  NavigatablePsiElement[] targets,
61                                  String title,
62                                  final String findUsagesTitle,
63                                  ListCellRenderer listRenderer,
64                                  @Nullable ListBackgroundUpdaterTask listUpdaterTask) {
65     JBPopup popup = navigateOrCreatePopup(targets, title, findUsagesTitle, listRenderer, listUpdaterTask);
66     if (popup != null) popup.show(new RelativePoint(e));
67   }
68
69   public static void openTargets(Editor e, NavigatablePsiElement[] targets, String title, final String findUsagesTitle, ListCellRenderer listRenderer) {
70     JBPopup popup = navigateOrCreatePopup(targets, title, findUsagesTitle, listRenderer, null);
71     if (popup != null) popup.showInBestPositionFor(e);
72   }
73
74   @Nullable
75   private static JBPopup navigateOrCreatePopup(final NavigatablePsiElement[] targets,
76                                                final String title,
77                                                final String findUsagesTitle,
78                                                final ListCellRenderer listRenderer,
79                                                @Nullable final ListBackgroundUpdaterTask listUpdaterTask) {
80     return navigateOrCreatePopup(targets, title, findUsagesTitle, listRenderer, listUpdaterTask, new Consumer<Object[]>() {
81       @Override
82       public void consume(Object[] selectedElements) {
83         for (Object element : selectedElements) {
84           PsiElement selected = (PsiElement)element;
85           LOG.assertTrue(selected.isValid());
86           ((NavigatablePsiElement)selected).navigate(true);
87         }
88       }
89     });
90   }
91
92   @Nullable
93   public static JBPopup navigateOrCreatePopup(@NotNull final NavigatablePsiElement[] targets,
94                                               final String title,
95                                               final String findUsagesTitle,
96                                               final ListCellRenderer listRenderer,
97                                               @Nullable final ListBackgroundUpdaterTask listUpdaterTask,
98                                               @NotNull final Consumer<Object[]> consumer) {
99     if (targets.length == 0) return null;
100     if (targets.length == 1) {
101       consumer.consume(targets);
102       return null;
103     }
104     final CollectionListModel<NavigatablePsiElement> model = new CollectionListModel<NavigatablePsiElement>(targets);
105     final JBListWithHintProvider list = new JBListWithHintProvider(model) {
106       @Override
107       protected PsiElement getPsiElementForHint(final Object selectedValue) {
108         return (PsiElement) selectedValue;
109       }
110     };
111
112     list.setTransferHandler(new TransferHandler(){
113       @Nullable
114       @Override
115       protected Transferable createTransferable(JComponent c) {
116         final Object[] selectedValues = list.getSelectedValues();
117         final PsiElement[] copy = new PsiElement[selectedValues.length];
118         for (int i = 0; i < selectedValues.length; i++) {
119           copy[i] = (PsiElement)selectedValues[i];
120         }
121         return new PsiCopyPasteManager.MyTransferable(copy);
122       }
123
124       @Override
125       public int getSourceActions(JComponent c) {
126         return COPY;
127       }
128     });
129
130     list.setCellRenderer(listRenderer);
131     list.setFont(ChooseByNameBase.getEditorFont());
132
133     final PopupChooserBuilder builder = new PopupChooserBuilder(list);
134     if (listRenderer instanceof PsiElementListCellRenderer) {
135       ((PsiElementListCellRenderer)listRenderer).installSpeedSearch(builder);
136     }
137
138     PopupChooserBuilder popupChooserBuilder = builder.
139       setTitle(title).
140       setMovable(true).
141       setResizable(true).
142       setItemChoosenCallback(new Runnable() {
143         @Override
144         public void run() {
145           int[] ids = list.getSelectedIndices();
146           if (ids == null || ids.length == 0) return;
147           Object[] selectedElements = list.getSelectedValues();
148           consumer.consume(selectedElements);
149         }
150       }).
151       setCancelCallback(new Computable<Boolean>() {
152         @Override
153         public Boolean compute() {
154           HintUpdateSupply.hideHint(list);
155           return true;
156         }
157       });
158     final Ref<UsageView> usageView = new Ref<UsageView>();
159     if (findUsagesTitle != null) {
160       popupChooserBuilder = popupChooserBuilder.setCouldPin(new Processor<JBPopup>() {
161         @Override
162         public boolean process(JBPopup popup) {
163           final List<NavigatablePsiElement> items = model.getItems();
164           usageView.set(FindUtil.showInUsageView(null, items.toArray(new PsiElement[items.size()]), findUsagesTitle, targets[0].getProject()));
165           popup.cancel();
166           return false;
167         }
168       });
169     }
170
171     final JBPopup popup = popupChooserBuilder.createPopup();
172
173     builder.getScrollPane().setBorder(null);
174     builder.getScrollPane().setViewportBorder(null);
175
176     if (listUpdaterTask != null) {
177       listUpdaterTask.init((AbstractPopup)popup, list, usageView);
178
179       ProgressManager.getInstance().run(listUpdaterTask);
180     }
181     return popup;
182   }
183 }