sticky documentation popup [take 1]
[fedora-idea.git] / platform / lang-impl / src / com / intellij / find / actions / ShowUsagesAction.java
blob69d744506b30bb003be063ea83995d89a6cf8ffd
1 /*
2 * Copyright 2000-2010 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.find.actions;
19 import com.intellij.codeInsight.hint.HintManager;
20 import com.intellij.codeInsight.hint.HintUtil;
21 import com.intellij.featureStatistics.FeatureUsageTracker;
22 import com.intellij.find.FindManager;
23 import com.intellij.find.findUsages.AbstractFindUsagesDialog;
24 import com.intellij.find.findUsages.FindUsagesHandler;
25 import com.intellij.find.findUsages.FindUsagesManager;
26 import com.intellij.find.impl.FindManagerImpl;
27 import com.intellij.openapi.Disposable;
28 import com.intellij.openapi.actionSystem.*;
29 import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
30 import com.intellij.openapi.editor.Editor;
31 import com.intellij.openapi.fileEditor.FileEditor;
32 import com.intellij.openapi.fileEditor.FileEditorLocation;
33 import com.intellij.openapi.fileEditor.TextEditor;
34 import com.intellij.openapi.keymap.KeymapUtil;
35 import com.intellij.openapi.project.Project;
36 import com.intellij.openapi.ui.popup.JBPopup;
37 import com.intellij.openapi.ui.popup.JBPopupFactory;
38 import com.intellij.openapi.ui.popup.PopupChooserBuilder;
39 import com.intellij.openapi.util.Comparing;
40 import com.intellij.openapi.util.Disposer;
41 import com.intellij.openapi.util.IconLoader;
42 import com.intellij.openapi.vfs.VirtualFile;
43 import com.intellij.openapi.wm.IdeFocusManager;
44 import com.intellij.psi.PsiDocumentManager;
45 import com.intellij.psi.PsiElement;
46 import com.intellij.psi.SmartPointerManager;
47 import com.intellij.psi.SmartPsiElementPointer;
48 import com.intellij.psi.search.ProjectScope;
49 import com.intellij.psi.search.PsiElementProcessor;
50 import com.intellij.psi.search.SearchScope;
51 import com.intellij.ui.InplaceButton;
52 import com.intellij.ui.SpeedSearchBase;
53 import com.intellij.ui.TableScrollingUtil;
54 import com.intellij.ui.awt.RelativePoint;
55 import com.intellij.usageView.UsageViewBundle;
56 import com.intellij.usages.*;
57 import com.intellij.usages.impl.GroupNode;
58 import com.intellij.usages.impl.NullUsage;
59 import com.intellij.usages.impl.UsageNode;
60 import com.intellij.usages.impl.UsageViewImpl;
61 import com.intellij.usages.rules.UsageFilteringRuleProvider;
62 import com.intellij.util.Icons;
63 import com.intellij.util.Processor;
64 import com.intellij.util.messages.MessageBusConnection;
65 import com.intellij.util.ui.Table;
66 import org.jetbrains.annotations.NonNls;
67 import org.jetbrains.annotations.NotNull;
69 import javax.swing.*;
70 import javax.swing.table.AbstractTableModel;
71 import javax.swing.table.TableColumn;
72 import java.awt.*;
73 import java.awt.event.ActionEvent;
74 import java.awt.event.ActionListener;
75 import java.util.*;
76 import java.util.List;
78 public class ShowUsagesAction extends AnAction {
79 private final boolean showSettingsDialogBefore;
81 private static final int USAGES_PAGE_SIZE = 100;
82 private static final Comparator<Object> USAGE_COMPARATOR = new Comparator<Object>() {
83 public int compare(Object c1, Object c2) {
84 Usage o1 = ((UsageNode)c1).getUsage();
85 Usage o2 = ((UsageNode)c2).getUsage();
86 if (o1 == NullUsage.INSTANCE) return 1;
87 if (o2 == NullUsage.INSTANCE) return -1;
89 VirtualFile v1 = UsageListCellRenderer.getVirtualFile(o1);
90 VirtualFile v2 = UsageListCellRenderer.getVirtualFile(o2);
91 String name1 = v1 == null ? null : v1.getName();
92 String name2 = v2 == null ? null : v2.getName();
93 int i = Comparing.compare(name1, name2);
94 if (i!=0) return i;
96 if (o1 instanceof Comparable && o2 instanceof Comparable) {
97 return ((Comparable)o1).compareTo(o2);
100 FileEditorLocation loc1 = o1.getLocation();
101 FileEditorLocation loc2 = o2.getLocation();
102 return Comparing.compare(loc1, loc2);
105 private static final Runnable HIDE_HINTS_ACTION = new Runnable() {
106 public void run() {
107 hideHints();
111 public ShowUsagesAction() {
112 setInjectedContext(true);
113 showSettingsDialogBefore = false;
116 public static class ShowSettings extends ShowUsagesAction {
117 public ShowSettings() {
118 super(true);
122 private ShowUsagesAction(boolean showDialogBefore) {
123 setInjectedContext(true);
124 showSettingsDialogBefore = showDialogBefore;
127 public void actionPerformed(AnActionEvent e) {
128 final Project project = e.getData(PlatformDataKeys.PROJECT);
129 if (project == null) return;
130 hideHints();
131 myWidth = -1;
132 final RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext());
133 PsiDocumentManager.getInstance(project).commitAllDocuments();
134 FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.usages");
136 UsageTarget[] usageTargets = e.getData(UsageView.USAGE_TARGETS_KEY);
137 final Editor editor = e.getData(PlatformDataKeys.EDITOR);
138 if (usageTargets == null) {
139 FindUsagesAction.chooseAmbiguousTargetAndPerform(project, editor, new PsiElementProcessor<PsiElement>() {
140 public boolean execute(final PsiElement element) {
141 startFindUsages(element, popupPosition, editor, USAGES_PAGE_SIZE);
142 return false;
146 else {
147 PsiElement element = ((PsiElementUsageTarget)usageTargets[0]).getElement();
148 if (element != null) {
149 startFindUsages(element, popupPosition, editor, USAGES_PAGE_SIZE);
154 private static void hideHints() {
155 HintManager.getInstance().hideHints(HintManager.HIDE_BY_ANY_KEY, false, false);
158 private void startFindUsages(@NotNull PsiElement element, RelativePoint popupPosition, Editor editor, int maxUsages) {
159 Project project = element.getProject();
160 FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager();
161 FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, false);
162 if (handler == null) return;
163 if (showSettingsDialogBefore) {
164 showDialogAndFindUsages(handler, popupPosition, editor, maxUsages);
165 return;
167 showElementUsages(handler, editor, popupPosition, maxUsages);
170 private void showElementUsages(@NotNull FindUsagesHandler handler, final Editor editor, final RelativePoint popupPosition, final int maxUsages) {
171 UsageViewPresentation presentation = new UsageViewPresentation();
172 presentation.setDetachedMode(true);
174 final UsageViewSettings usageViewSettings = UsageViewSettings.getInstance();
175 final UsageViewSettings save = new UsageViewSettings();
177 save.loadState(usageViewSettings);
178 usageViewSettings.GROUP_BY_FILE_STRUCTURE = false;
179 usageViewSettings.GROUP_BY_MODULE = false;
180 usageViewSettings.GROUP_BY_PACKAGE = false;
181 usageViewSettings.GROUP_BY_USAGE_TYPE = false;
183 UsageViewManager manager = UsageViewManager.getInstance(handler.getProject());
184 final UsageViewImpl usageView = (UsageViewImpl)manager.createUsageView(UsageTarget.EMPTY_ARRAY, Usage.EMPTY_ARRAY, presentation, null);
186 Disposer.register(usageView, new Disposable() {
187 public void dispose() {
188 usageViewSettings.GROUP_BY_FILE_STRUCTURE = save.GROUP_BY_FILE_STRUCTURE;
189 usageViewSettings.GROUP_BY_MODULE = save.GROUP_BY_MODULE;
190 usageViewSettings.GROUP_BY_PACKAGE = save.GROUP_BY_PACKAGE;
191 usageViewSettings.GROUP_BY_USAGE_TYPE = save.GROUP_BY_USAGE_TYPE;
195 final List<Usage> usages = new ArrayList<Usage>();
196 final Set<UsageNode> visibleNodes = new LinkedHashSet<UsageNode>();
197 Processor<Usage> collect = new Processor<Usage>() {
198 public boolean process(@NotNull Usage usage) {
199 synchronized (usages) {
200 if (visibleNodes.size() > maxUsages) return false;
201 UsageNode node = usageView.doAppendUsage(usage);
202 if (node != null) {
203 if (visibleNodes.size() == maxUsages) {
204 usageView.removeUsage(usage);
205 visibleNodes.add(UsageViewImpl.NULL_NODE);
206 return false;
208 visibleNodes.add(node);
210 usages.add(usage);
212 return true;
215 FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(handler.getProject())).getFindUsagesManager();
216 presentation = findUsagesManager.processUsages(handler, collect);
217 if (presentation == null) {
218 Disposer.dispose(usageView);
219 return;
221 final String title = presentation.getTabText();
223 JBPopup popup = createUsagePopup(usages, visibleNodes, title, handler, editor, popupPosition, maxUsages, usageView);
224 if (popup != null) {
225 popup.show(popupPosition);
229 private void showHint(String text, final Editor editor, final RelativePoint popupPosition, FindUsagesHandler handler, int maxUsages) {
230 JComponent label = createHintComponent(text, handler, popupPosition, editor, HIDE_HINTS_ACTION, maxUsages);
231 if (editor == null) {
232 HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY |
233 HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0);
235 else {
236 HintManager.getInstance().showInformationHint(editor, label);
240 private JComponent createHintComponent(String text, final FindUsagesHandler handler, final RelativePoint popupPosition, final Editor editor,
241 final Runnable cancelAction,
242 int maxUsages) {
243 JLabel label = HintUtil.createInformationLabel(text);
244 InplaceButton button = createSettingsButton(handler, popupPosition, editor, maxUsages, cancelAction);
245 JPanel panel = new JPanel(new BorderLayout());
246 button.setBackground(label.getBackground());
247 panel.setBackground(label.getBackground());
248 label.setOpaque(false);
249 label.setBorder(null);
250 panel.setBorder(HintUtil.createHintBorder());
251 panel.add(label, BorderLayout.CENTER);
252 panel.add(button, BorderLayout.EAST);
253 return panel;
256 private InplaceButton createSettingsButton(final FindUsagesHandler handler, final RelativePoint popupPosition,
257 final Editor editor,
258 final int maxUsages,
259 final Runnable cancelAction) {
260 String shortcutText = "";
261 KeyboardShortcut shortcut = getSettingsShortcut();
262 if (shortcut != null) {
263 shortcutText = "(" + KeymapUtil.getShortcutText(shortcut) + ")";
265 return new InplaceButton("Options..." + shortcutText, IconLoader.getIcon("/general/ideOptions.png"), new ActionListener() {
266 public void actionPerformed(ActionEvent e) {
267 SwingUtilities.invokeLater(new Runnable() {
268 public void run() {
269 showDialogAndFindUsages(handler, popupPosition, editor, maxUsages);
272 cancelAction.run();
277 private void showDialogAndFindUsages(FindUsagesHandler handler, RelativePoint popupPosition, Editor editor, int maxUsages) {
278 AbstractFindUsagesDialog dialog = handler.getFindUsagesDialog(false, false, false);
279 dialog.show();
280 if (dialog.isOK()) {
281 dialog.calcFindUsagesOptions();
282 showElementUsages(handler, editor, popupPosition, maxUsages);
286 private static String searchScopePresentableName(final FindUsagesHandler handler) {
287 SearchScope searchScope = FindUsagesManager.getCurrentSearchScope(handler);
288 if (searchScope == null) searchScope = ProjectScope.getAllScope(handler.getProject());
289 return searchScope.getDisplayName();
292 private JBPopup createUsagePopup(final List<Usage> usages,
293 Set<UsageNode> visibleNodes,
294 final String title,
295 final FindUsagesHandler handler,
296 final Editor editor,
297 final RelativePoint popupPosition,
298 final int maxUsages,
299 final UsageViewImpl usageView) {
300 boolean hasMore = visibleNodes.remove(UsageViewImpl.NULL_NODE);
302 final Project project = handler.getProject();
304 if (visibleNodes.isEmpty()) {
305 if (usages.isEmpty()) {
306 String text = UsageViewBundle.message("no.usages.found.in", searchScopePresentableName(handler));
307 showHint(text, editor, popupPosition, handler, maxUsages);
308 Disposer.dispose(usageView);
309 return null;
311 else {
312 // all usages filtered out
315 if (visibleNodes.size() == 1 && usages.size() == 1) {
316 //the only usage
317 Usage usage = visibleNodes.iterator().next().getUsage();
318 navigateAndHint(usage, UsageViewBundle.message("show.usages.only.usage", searchScopePresentableName(handler)), handler, popupPosition,
319 maxUsages);
320 Disposer.dispose(usageView);
321 return null;
323 if (visibleNodes.size() == 1 && usages.size() >= 1) {
324 // usage view can filter usages down to one
325 Usage usage = visibleNodes.iterator().next().getUsage();
326 navigateAndHint(usage, UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), searchScopePresentableName(handler)),
327 handler, popupPosition, maxUsages);
328 Disposer.dispose(usageView);
329 return null;
332 if (hasMore) {
333 usages.add(NullUsage.INSTANCE);
334 visibleNodes.add(UsageViewImpl.NULL_NODE);
336 addUsageNodes(usageView.getRoot(), usageView, new ArrayList<UsageNode>());
339 final JTable table = new MyTable();
340 TableScrollingUtil.installActions(table);
341 final Vector<Object> data = new Vector<Object>();
342 setModel(table, usages, visibleNodes, usageView, data);
344 final Runnable navigateRunnable = new Runnable() {
345 public void run() {
346 int[] selected = table.getSelectedRows();
347 for (int i : selected) {
348 Object value = table.getValueAt(i,0);
349 if (value instanceof UsageNode) {
350 Usage usage = ((UsageNode)value).getUsage();
351 if (usage == NullUsage.INSTANCE) {
352 appendMoreUsages(editor, popupPosition, handler, maxUsages);
353 return;
355 navigateAndHint(usage, null, handler, popupPosition, maxUsages);
361 SpeedSearchBase<JTable> speedSearch = new SpeedSearchBase<JTable>(table) {
362 protected int getSelectedIndex() {
363 return table.getSelectedRow();
366 protected Object[] getAllElements() {
367 return data.toArray(new Object[data.size()]);
370 protected String getElementText(Object element) {
371 if (!(element instanceof UsageNode)) return element.toString();
372 UsageNode node = (UsageNode)element;
373 GroupNode group = (GroupNode)node.getParent();
374 return node.getUsage().getPresentation().getPlainText() + group.toString();
377 protected void selectElement(Object element, String selectedText) {
378 int i = data.indexOf(element);
379 if (i == -1) return;
380 table.getSelectionModel().setSelectionInterval(i, i);
383 speedSearch.setComparator(new SpeedSearchBase.SpeedSearchComparator(false));
385 PopupChooserBuilder builder = new PopupChooserBuilder(table);
386 if (title != null) {
387 String s;
388 if (hasMore) {
389 s = "<html><body><b>Some</b> " + title + " " + "<b>(Only " + (visibleNodes.size() - 1) + " usages shown)</b></body></html>";
391 else {
392 s = title + " (" + usages.size() + " usages found)";
394 builder.setTitle(s);
397 builder.setMovable(true).setResizable(true);
398 builder.setItemChoosenCallback(navigateRunnable);
399 final JBPopup[] popup = new JBPopup[1];
400 ActionListener editSettings = new ActionListener() {
401 public void actionPerformed(ActionEvent e) {
402 popup[0].cancel();
403 SwingUtilities.invokeLater(new Runnable() {
404 public void run() {
405 showDialogAndFindUsages(handler, popupPosition, editor, maxUsages);
413 KeyboardShortcut shortcut = getSettingsShortcut();
414 if (shortcut != null) {
415 builder.registerKeyboardAction(shortcut.getFirstKeyStroke(), editSettings);
418 InplaceButton button = createSettingsButton(handler, popupPosition, editor, maxUsages, new Runnable() {
419 public void run() {
420 popup[0].cancel();
423 builder.setCommandButton(button);
425 DefaultActionGroup filters = new DefaultActionGroup();
426 usageView.addFilteringActions(filters);
428 filters.add(new AnAction("Open Find Usages Toolwindow", "Show all usages in a separate toolwindow", IconLoader.getIcon("/general/toolWindowFind.png")) {
430 AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_USAGES);
431 setShortcutSet(action.getShortcutSet());
433 @Override
434 public void actionPerformed(AnActionEvent e) {
435 hideHints();
436 popup[0].cancel();
437 FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager();
438 FindUsagesManager.SearchData data = new FindUsagesManager.SearchData();
439 data.myOptions = handler.getFindUsagesOptions();
440 SmartPsiElementPointer<PsiElement> pointer =
441 SmartPointerManager.getInstance(project).createSmartPsiElementPointer(handler.getPsiElement());
442 data.myElements = new SmartPsiElementPointer[]{pointer};
443 findUsagesManager.rerunAndRecallFromHistory(data);
447 ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.USAGE_VIEW_TOOLBAR, filters, true);
448 actionToolbar.setReservePlaceAutoPopupIcon(false);
449 final JComponent toolBar = actionToolbar.getComponent();
450 toolBar.setOpaque(false);
451 builder.setSettingButton(toolBar);
453 popup[0] = builder.createPopup();
454 Disposer.register(popup[0], usageView);
455 for (AnAction action : filters.getChildren(null)) {
456 action.unregisterCustomShortcutSet(usageView.getComponent());
457 action.registerCustomShortcutSet(action.getShortcutSet(), popup[0].getContent());
460 final MessageBusConnection messageBusConnection = project.getMessageBus().connect(usageView);
461 messageBusConnection.subscribe(UsageFilteringRuleProvider.RULES_CHANGED, new Runnable() {
462 public void run() {
463 rebuildPopup(usageView, usages, table, popup[0]);
467 return popup[0];
470 private static int setModel(JTable table, List<Usage> usages, Collection<UsageNode> visibleNodes, UsageViewImpl usageView,
471 final Vector<Object> data) {
472 if (visibleNodes.isEmpty()) {
473 data.add(UsageViewBundle.message("usages.were.filtered.out", usages.size()));
475 else {
476 data.addAll(visibleNodes);
478 Collections.sort(data, USAGE_COMPARATOR);
479 AbstractTableModel model = new AbstractTableModel() {
480 public int getRowCount() {
481 return data.size();
484 public int getColumnCount() {
485 return data.get(0) instanceof UsageNode ? 3 : 1;
488 public Object getValueAt(int rowIndex, int columnIndex) {
489 return data.get(rowIndex);
492 table.setModel(model);
494 table.setRowHeight(Icons.CLASS_ICON.getIconHeight()+2);
495 table.setShowGrid(false);
496 table.setShowVerticalLines(false);
497 table.setShowHorizontalLines(false);
498 table.setTableHeader(null);
499 table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
500 ShowUsagesTableCellRenderer renderer = new ShowUsagesTableCellRenderer(usageView);
501 for (int i=0;i<table.getColumnModel().getColumnCount();i++) {
502 TableColumn column = table.getColumnModel().getColumn(i);
503 column.setCellRenderer(renderer);
505 table.setIntercellSpacing(new Dimension(0, 0));
507 int colsNum = table.getColumnModel().getColumnCount();
509 int totalWidth = 0;
510 for (int col = 0; col < colsNum -1; col++) {
511 TableColumn column = table.getColumnModel().getColumn(col);
512 int preferred = column.getPreferredWidth();
513 int width = Math.max(preferred, calcMaxWidth(table, col));
514 totalWidth += width;
515 column.setMinWidth(width);
516 column.setMaxWidth(width);
517 column.setWidth(width);
518 column.setPreferredWidth(width);
521 totalWidth += calcMaxWidth(table, colsNum - 1);
523 Dimension dimension = new Dimension(totalWidth, table.getRowHeight() * data.size());
524 table.setMinimumSize(dimension);
525 table.setSize(dimension);
526 table.setPreferredSize(dimension);
527 table.setMaximumSize(dimension);
528 table.setPreferredScrollableViewportSize(dimension);
530 return totalWidth;
533 private static int calcMaxWidth(JTable table, int col) {
534 TableColumn column = table.getColumnModel().getColumn(col);
535 int width = 0;
536 for (int row = 0; row < table.getRowCount(); row++) {
537 Component component = table.prepareRenderer(column.getCellRenderer(), row, col);
539 int rendererWidth = component.getPreferredSize().width;
540 width = Math.max(width, rendererWidth + table.getIntercellSpacing().width);
542 return width;
545 private int myWidth;
546 private void rebuildPopup(final UsageViewImpl usageView, final List<Usage> usages, final JTable table, final JBPopup popup) {
547 SwingUtilities.invokeLater(new Runnable() {
548 public void run() {
549 JComponent content = popup.getContent();
550 Window window = SwingUtilities.windowForComponent(content);
551 Dimension d = window.getSize();
553 final List<UsageNode> nodes = new ArrayList<UsageNode>();
554 addUsageNodes(usageView.getRoot(), usageView, nodes);
556 int old = table.getModel().getRowCount();
557 Vector<Object> data = new Vector<Object>();
558 int width = setModel(table, usages, nodes, usageView, data);
561 if (myWidth == -1) myWidth = width;
562 Dimension newDim = new Dimension(Math.max(width, d.width + width - myWidth), d.height + (data.size() - old) * table.getRowHeight());
563 myWidth = width;
564 window.setSize(newDim);
565 window.validate();
566 window.repaint();
567 table.revalidate();
568 table.repaint();
573 private void appendMoreUsages(Editor editor, RelativePoint popupPosition, FindUsagesHandler handler, int maxUsages) {
574 showElementUsages(handler, editor, popupPosition, maxUsages+USAGES_PAGE_SIZE);
577 private static KeyboardShortcut getSettingsShortcut() {
578 return ActionManagerEx.getInstanceEx().getKeyboardShortcut("ShowUsagesSettings");
581 private static void addUsageNodes(GroupNode root, final UsageViewImpl usageView, List<UsageNode> outNodes) {
582 for (UsageNode node : root.getUsageNodes()) {
583 Usage usage = node.getUsage();
584 if (usageView.isVisible(usage)) {
585 node.setParent(root);
586 outNodes.add(node);
589 for (GroupNode groupNode : root.getSubGroups()) {
590 groupNode.setParent(root);
591 addUsageNodes(groupNode, usageView, outNodes);
595 public void update(AnActionEvent e){
596 FindUsagesInFileAction.updateFindUsagesAction(e);
599 private void navigateAndHint(Usage usage, final String hint, final FindUsagesHandler handler,
600 final RelativePoint popupPosition,
601 final int maxUsages) {
602 usage.navigate(true);
603 if (hint == null) return;
604 FileEditorLocation location = usage.getLocation();
605 FileEditor newFileEditor = location == null ? null : location.getEditor();
606 final Editor newEditor = newFileEditor instanceof TextEditor ? ((TextEditor)newFileEditor).getEditor() : null;
607 if (newEditor != null) {
608 final Project project = handler.getProject();
609 //opening editor is performing in invokeLater
610 IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() {
611 public void run() {
612 newEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
613 public void run() {
614 // after new editor created, some editor resizing events are still bubbling. To prevent hiding hint, invokeLater this
615 IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() {
616 public void run() {
617 showHint(hint, newEditor, popupPosition, handler, maxUsages);
627 static class MyTable extends Table implements DataProvider {
628 @Override
629 public boolean getScrollableTracksViewportWidth() {
630 return true;
633 public Object getData(@NonNls String dataId) {
634 if (LangDataKeys.PSI_ELEMENT.is(dataId)) {
635 final int[] selected = getSelectedRows();
636 if (selected.length == 1) {
637 final Object at = getValueAt(selected[0], 0);
638 if (at instanceof UsageNode) {
639 final Usage usage = ((UsageNode)at).getUsage();
640 if (usage instanceof UsageInfo2UsageAdapter) {
641 final PsiElement element = ((UsageInfo2UsageAdapter)usage).getElement();
642 if (element != null) {
643 final PsiElement view = UsageToPsiElementProvider.findAppropriateParentFrom(element);
644 return view == null ? element : view;
650 return null;