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
.internal
.psiView
;
18 import com
.intellij
.lang
.ASTNode
;
19 import com
.intellij
.lang
.Language
;
20 import com
.intellij
.lang
.LanguageUtil
;
21 import com
.intellij
.openapi
.actionSystem
.AnAction
;
22 import com
.intellij
.openapi
.actionSystem
.AnActionEvent
;
23 import com
.intellij
.openapi
.actionSystem
.DefaultActionGroup
;
24 import com
.intellij
.openapi
.actionSystem
.Presentation
;
25 import com
.intellij
.openapi
.actionSystem
.ex
.ComboBoxAction
;
26 import com
.intellij
.openapi
.application
.ApplicationManager
;
27 import com
.intellij
.openapi
.editor
.*;
28 import com
.intellij
.openapi
.editor
.event
.*;
29 import com
.intellij
.openapi
.editor
.markup
.*;
30 import com
.intellij
.openapi
.extensions
.Extensions
;
31 import com
.intellij
.openapi
.fileTypes
.*;
32 import com
.intellij
.openapi
.fileTypes
.impl
.AbstractFileType
;
33 import com
.intellij
.openapi
.project
.DumbAware
;
34 import com
.intellij
.openapi
.project
.Project
;
35 import com
.intellij
.openapi
.ui
.DialogWrapper
;
36 import com
.intellij
.openapi
.ui
.Messages
;
37 import com
.intellij
.openapi
.util
.Disposer
;
38 import com
.intellij
.openapi
.util
.SystemInfo
;
39 import com
.intellij
.openapi
.util
.TextRange
;
40 import com
.intellij
.openapi
.wm
.IdeFocusManager
;
41 import com
.intellij
.psi
.PsiElement
;
42 import com
.intellij
.psi
.PsiFile
;
43 import com
.intellij
.psi
.PsiFileFactory
;
44 import com
.intellij
.psi
.PsiReference
;
45 import com
.intellij
.psi
.search
.FilenameIndex
;
46 import com
.intellij
.psi
.search
.GlobalSearchScope
;
47 import com
.intellij
.psi
.util
.PsiUtilBase
;
48 import com
.intellij
.ui
.SortedComboBoxModel
;
49 import com
.intellij
.ui
.TitledBorderWithMnemonic
;
50 import com
.intellij
.ui
.TreeSpeedSearch
;
51 import com
.intellij
.ui
.treeStructure
.Tree
;
52 import com
.intellij
.util
.IncorrectOperationException
;
53 import com
.intellij
.util
.ui
.UIUtil
;
54 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
55 import org
.jetbrains
.annotations
.NotNull
;
56 import org
.jetbrains
.annotations
.Nullable
;
59 import javax
.swing
.event
.ListSelectionEvent
;
60 import javax
.swing
.event
.ListSelectionListener
;
61 import javax
.swing
.event
.TreeSelectionEvent
;
62 import javax
.swing
.event
.TreeSelectionListener
;
63 import javax
.swing
.tree
.*;
65 import java
.awt
.event
.*;
67 import java
.util
.List
;
70 * @author Konstantin Bulenkov
72 public class PsiViewerDialog
extends DialogWrapper
{
73 private final Project myProject
;
75 private final Tree myTree
;
76 private final ViewerTreeBuilder myTreeBuilder
;
78 private final JList myRefs
;
79 private static String REFS_CACHE
= "References Resolve Cache";
81 private Editor myEditor
;
82 private String myLastParsedText
= null;
84 private JCheckBox myShowWhiteSpacesBox
;
85 private JPanel myStructureTreePanel
;
86 private JPanel myTextPanel
;
87 private JPanel myPanel
;
88 private JCheckBox myShowTreeNodesCheckBox
;
89 private JComboBox myDialectsComboBox
;
90 private JPanel myReferencesPanel
;
91 private JPanel myButtonPanel
;
92 private Presentation myPresentation
= new Presentation();
93 private Map
<String
, Object
> handlers
= new HashMap
<String
, Object
>();
94 private DefaultActionGroup myGroup
;
95 private Language
[] myLanguageDialects
;
96 private final Color SELECTION_BG_COLOR
= new Color(0, 51, 51);
97 private static final Comparator
<Language
> DIALECTS_COMPARATOR
= new Comparator
<Language
>() {
98 public int compare(final Language o1
, final Language o2
) {
99 if (o1
== null) return o2
== null ?
0 : -1;
100 if (o2
== null) return 1;
101 return o1
.getID().compareTo(o2
.getID());
104 private EditorListener myEditorListener
= new EditorListener();
105 private int myLastParsedTextHashCode
= 17;
106 private int myNewDocumentHashCode
= 11;
109 private static PsiElement
findCommonParent(PsiElement start
, PsiElement end
) {
110 final TextRange range
= end
.getTextRange();
111 while (start
!= null && !start
.getTextRange().contains(range
)) {
112 start
= start
.getParent();
117 public PsiViewerDialog(Project project
, boolean modal
) {
118 super(project
, true);
119 setTitle("PSI Viewer");
121 myTree
= new Tree(new DefaultTreeModel(new DefaultMutableTreeNode()));
122 UIUtil
.setLineStyleAngled(myTree
);
123 myTree
.setRootVisible(false);
124 myTree
.setShowsRootHandles(true);
126 ToolTipManager
.sharedInstance().registerComponent(myTree
);
127 TreeUtil
.installActions(myTree
);
128 new TreeSpeedSearch(myTree
);
129 myTreeBuilder
= new ViewerTreeBuilder(project
, myTree
);
131 myTree
.addTreeSelectionListener(new MyTreeSelectionListener());
133 JScrollPane scrollPane
= new JScrollPane(myTree
);
134 JPanel panel
= new JPanel(new BorderLayout());
135 panel
.add(scrollPane
, BorderLayout
.CENTER
);
136 myStructureTreePanel
.setLayout(new BorderLayout());
137 myStructureTreePanel
.add(panel
, BorderLayout
.CENTER
);
139 myRefs
= new JList(new DefaultListModel());
140 JScrollPane refScrollPane
= new JScrollPane(myRefs
);
141 JPanel refPanel
= new JPanel(new BorderLayout());
142 refPanel
.add(refScrollPane
, BorderLayout
.CENTER
);
143 myReferencesPanel
.setLayout(new BorderLayout());
144 myReferencesPanel
.add(refPanel
, BorderLayout
.CENTER
);
145 final GoToListener listener
= new GoToListener();
146 myRefs
.addKeyListener(listener
);
147 myRefs
.addMouseListener(listener
);
148 myRefs
.getSelectionModel().addListSelectionListener(listener
);
149 myRefs
.setCellRenderer(new DefaultListCellRenderer() {
150 public Component
getListCellRendererComponent(JList list
, Object value
, int index
, boolean isSelected
, boolean cellHasFocus
) {
151 final Component comp
= super.getListCellRendererComponent(list
, value
, index
, isSelected
, cellHasFocus
);
152 if (resolve(index
) == null) {
153 comp
.setForeground(Color
.red
);
160 setOKButtonText("&Build PSI Tree");
164 protected String
getDimensionServiceKey() {
165 return "#com.intellij.internal.psiView.PsiViewerDialog";
168 public JComponent
getPreferredFocusedComponent() {
169 return myEditor
.getContentComponent();
172 private void updatePresentation(Presentation p
) {
173 myPresentation
.setText(p
.getText());
174 myPresentation
.setIcon(p
.getIcon());
177 protected void init() {
179 final List
<Presentation
> items
= new ArrayList
<Presentation
>();
180 final EditorFactory editorFactory
= EditorFactory
.getInstance();
181 final Document document
= editorFactory
.createDocument("");
182 myEditor
= editorFactory
.createEditor(document
, myProject
);
183 myEditor
.getSettings().setFoldingOutlineShown(false);
184 document
.addDocumentListener(myEditorListener
);
185 myEditor
.getSelectionModel().addSelectionListener(myEditorListener
);
186 myEditor
.getCaretModel().addCaretListener(myEditorListener
);
188 for (PsiViewerExtension extension
: Extensions
.getExtensions(PsiViewerExtension
.EP_NAME
)) {
189 final Presentation p
= new Presentation(extension
.getName());
190 p
.setIcon(extension
.getIcon());
191 handlers
.put(p
.getText(), extension
);
195 for (FileType fileType
: FileTypeManager
.getInstance().getRegisteredFileTypes()) {
196 if (fileType
!= StdFileTypes
.GUI_DESIGNER_FORM
&&
197 fileType
!= StdFileTypes
.IDEA_MODULE
&&
198 fileType
!= StdFileTypes
.IDEA_PROJECT
&&
199 fileType
!= StdFileTypes
.IDEA_WORKSPACE
&&
200 fileType
!= FileTypes
.ARCHIVE
&&
201 fileType
!= FileTypes
.UNKNOWN
&&
202 fileType
!= FileTypes
.PLAIN_TEXT
&&
203 !(fileType
instanceof AbstractFileType
) &&
204 !fileType
.isBinary() &&
205 !fileType
.isReadOnly()) {
206 final Presentation p
= new Presentation(fileType
.getName() + " file");
207 p
.setIcon(fileType
.getIcon());
208 handlers
.put(p
.getText(), fileType
);
213 final Presentation
[] popupItems
= items
.toArray(new Presentation
[items
.size()]);
214 Arrays
.sort(popupItems
, new Comparator
<Presentation
>() {
215 public int compare(Presentation p1
, Presentation p2
) {
216 return p1
.getText().toUpperCase().compareTo(p2
.getText().toUpperCase());
220 final ViewerTreeStructure treeStructure
= (ViewerTreeStructure
)myTreeBuilder
.getTreeStructure();
221 myShowWhiteSpacesBox
.addActionListener(new ActionListener() {
222 public void actionPerformed(ActionEvent e
) {
223 treeStructure
.setShowWhiteSpaces(myShowWhiteSpacesBox
.isSelected());
224 myTreeBuilder
.queueUpdate();
227 myShowTreeNodesCheckBox
.addActionListener(new ActionListener() {
228 public void actionPerformed(ActionEvent e
) {
229 treeStructure
.setShowTreeNodes(myShowTreeNodesCheckBox
.isSelected());
230 myTreeBuilder
.queueUpdate();
233 myTextPanel
.setLayout(new BorderLayout());
234 myTextPanel
.add(myEditor
.getComponent(), BorderLayout
.CENTER
);
236 myGroup
= new DefaultActionGroup();
237 for (final Presentation popupItem
: popupItems
) {
238 myGroup
.add(new PopupItemAction(popupItem
));
241 final PsiViewerSettings settings
= PsiViewerSettings
.getSettings();
242 final String type
= settings
.type
;
243 for (Presentation popupItem
: popupItems
) {
244 if (popupItem
.getText().equals(type
)) {
245 updatePresentation(popupItem
);
250 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
252 myEditor
.getDocument().setText(settings
.text
);
256 myShowWhiteSpacesBox
.setSelected(settings
.showWhiteSpaces
);
257 myShowTreeNodesCheckBox
.setSelected(settings
.showTreeNodes
);
259 final ChoosePsiTypeButton typeButton
= new ChoosePsiTypeButton();
260 myButtonPanel
.add(typeButton
.createCustomComponent(myPresentation
), BorderLayout
.CENTER
);
262 updateDialectsCombo();
263 if (myDialectsComboBox
.isVisible()) {
264 for (int i
= 0; i
< myLanguageDialects
.length
; i
++) {
265 if (settings
.dialect
.equals(myLanguageDialects
[i
].toString())) {
266 myDialectsComboBox
.setSelectedIndex(i
);
272 registerCustomKeyboardActions();
276 private void registerCustomKeyboardActions() {
277 final Component component
= myButtonPanel
.getComponents()[0];
278 if (component
instanceof JComponent
) {
279 final Component button
= ((JComponent
)component
).getComponents()[0];
280 if (button
instanceof JButton
) {
281 final JButton jButton
= (JButton
)button
;
282 final int mask
= SystemInfo
.isMac ? KeyEvent
.META_DOWN_MASK
: KeyEvent
.ALT_DOWN_MASK
;
283 registerKeyboardAction(new ActionListener() {
284 public void actionPerformed(ActionEvent e
) {
287 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_P
, mask
));
289 registerKeyboardAction(new ActionListener() {
290 public void actionPerformed(ActionEvent e
) {
293 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_T
, mask
));
295 registerKeyboardAction(new ActionListener() {
296 public void actionPerformed(ActionEvent e
) {
299 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_S
, mask
));
301 registerKeyboardAction(new ActionListener() {
302 public void actionPerformed(ActionEvent e
) {
305 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_S
, mask
));
308 registerKeyboardAction(new ActionListener() {
309 public void actionPerformed(ActionEvent e
) {
312 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_S
, mask
));
314 registerKeyboardAction(new ActionListener() {
315 public void actionPerformed(ActionEvent e
) {
318 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_R
, mask
));
320 registerKeyboardAction(new ActionListener() {
321 public void actionPerformed(ActionEvent e
) {
322 if (myRefs
.isFocusOwner()) {
325 else if (myTree
.isFocusOwner()) {
329 }, KeyStroke
.getKeyStroke(KeyEvent
.VK_TAB
, 0));
334 private void registerKeyboardAction(ActionListener actionListener
, KeyStroke keyStroke
) {
335 getRootPane().registerKeyboardAction(actionListener
, keyStroke
, JComponent
.WHEN_IN_FOCUSED_WINDOW
);
338 private void focusEditor() {
339 IdeFocusManager
.getInstance(myProject
).requestFocus(myEditor
.getContentComponent(), true);
342 private void focusTree() {
343 IdeFocusManager
.getInstance(myProject
).requestFocus(myTree
, true);
346 private void focusRefs() {
347 IdeFocusManager
.getInstance(myProject
).requestFocus(myRefs
, true);
348 if (myRefs
.getModel().getSize() > 0) {
349 if (myRefs
.getSelectedIndex() == -1) {
350 myRefs
.setSelectedIndex(0);
355 private void initBorders() {
356 myTextPanel
.setBorder(new TitledBorderWithMnemonic("&Text"));
357 myStructureTreePanel
.setBorder(new TitledBorderWithMnemonic("PSI &Structure"));
358 myReferencesPanel
.setBorder(new TitledBorderWithMnemonic("&References"));
362 private PsiElement
getPsiElement() {
363 final TreePath path
= myTree
.getSelectionPath();
364 return path
== null ?
null : getPsiElement((DefaultMutableTreeNode
)path
.getLastPathComponent());
368 private PsiElement
getPsiElement(DefaultMutableTreeNode node
) {
369 if (node
.getUserObject() instanceof ViewerNodeDescriptor
) {
370 ViewerNodeDescriptor descriptor
= (ViewerNodeDescriptor
)node
.getUserObject();
371 Object elementObject
= descriptor
.getElement();
372 return elementObject
instanceof PsiElement
373 ?
(PsiElement
)elementObject
374 : elementObject
instanceof ASTNode ?
((ASTNode
)elementObject
).getPsi() : null;
379 private void updateDialectsCombo() {
380 final SortedComboBoxModel
<Language
> model
= new SortedComboBoxModel
<Language
>(DIALECTS_COMPARATOR
);
381 final Object handler
= getHandler();
382 if (handler
instanceof LanguageFileType
) {
383 final Language baseLang
= ((LanguageFileType
)handler
).getLanguage();
384 myLanguageDialects
= LanguageUtil
.getLanguageDialects(baseLang
);
385 Arrays
.sort(myLanguageDialects
, DIALECTS_COMPARATOR
);
386 model
.setAll(myLanguageDialects
);
388 myDialectsComboBox
.setModel(model
);
389 myDialectsComboBox
.setVisible(model
.getSize() > 1);
390 if (!myDialectsComboBox
.isVisible()) {
391 myLanguageDialects
= new Language
[0];
395 protected JComponent
createCenterPanel() {
399 private Object
getHandler() {
400 return handlers
.get(myPresentation
.getText());
403 protected void doOKAction() {
404 final String text
= myEditor
.getDocument().getText();
405 if (text
.trim().length() == 0) return;
407 myLastParsedText
= text
;
408 myLastParsedTextHashCode
= text
.hashCode();
409 myNewDocumentHashCode
= myLastParsedTextHashCode
;
410 PsiElement rootElement
= null;
411 final Object handler
= getHandler();
414 if (handler
instanceof PsiViewerExtension
) {
415 final PsiViewerExtension ext
= (PsiViewerExtension
)handler
;
416 rootElement
= ext
.createElement(myProject
, text
);
418 else if (handler
instanceof FileType
) {
419 final FileType type
= (FileType
)handler
;
420 if (type
instanceof LanguageFileType
) {
421 final Language language
= ((LanguageFileType
)type
).getLanguage();
422 final Language dialect
= (Language
)myDialectsComboBox
.getSelectedItem();
423 rootElement
= PsiFileFactory
.getInstance(myProject
)
424 .createFileFromText("Dummy." + type
.getDefaultExtension(), dialect
== null ? language
: dialect
, text
);
427 rootElement
= PsiFileFactory
.getInstance(myProject
).createFileFromText("Dummy." + type
.getDefaultExtension(), text
);
432 catch (IncorrectOperationException e1
) {
434 Messages
.showMessageDialog(myProject
, e1
.getMessage(), "Error", Messages
.getErrorIcon());
436 ViewerTreeStructure structure
= (ViewerTreeStructure
)myTreeBuilder
.getTreeStructure();
437 structure
.setRootPsiElement(rootElement
);
439 myTreeBuilder
.queueUpdate();
440 myTree
.setRootVisible(true);
442 myTree
.setRootVisible(false);
445 private class MyTreeSelectionListener
implements TreeSelectionListener
{
446 private final TextAttributes myAttributes
;
448 public MyTreeSelectionListener() {
449 myAttributes
= new TextAttributes();
450 myAttributes
.setBackgroundColor(SELECTION_BG_COLOR
);
451 myAttributes
.setForegroundColor(Color
.white
);
454 public void valueChanged(TreeSelectionEvent e
) {
455 if (!myEditor
.getDocument().getText().equals(myLastParsedText
)) return;
456 TreePath path
= myTree
.getSelectionPath();
462 DefaultMutableTreeNode node
= (DefaultMutableTreeNode
)path
.getLastPathComponent();
463 if (!(node
.getUserObject() instanceof ViewerNodeDescriptor
)) return;
464 ViewerNodeDescriptor descriptor
= (ViewerNodeDescriptor
)node
.getUserObject();
465 Object elementObject
= descriptor
.getElement();
466 final PsiElement element
= elementObject
instanceof PsiElement
467 ?
(PsiElement
)elementObject
468 : elementObject
instanceof ASTNode ?
((ASTNode
)elementObject
).getPsi() : null;
469 if (element
!= null) {
470 TextRange range
= element
.getTextRange();
471 int start
= range
.getStartOffset();
472 int end
= range
.getEndOffset();
473 final ViewerTreeStructure treeStructure
= (ViewerTreeStructure
)myTreeBuilder
.getTreeStructure();
474 PsiElement rootPsiElement
= treeStructure
.getRootPsiElement();
475 if (rootPsiElement
!= null) {
476 int baseOffset
= rootPsiElement
.getTextRange().getStartOffset();
481 final int textLength
= myEditor
.getDocument().getTextLength();
482 if (end
<= textLength
) {
483 myEditor
.getMarkupModel()
484 .addRangeHighlighter(start
, end
, HighlighterLayer
.FIRST
+ 1, myAttributes
, HighlighterTargetArea
.EXACT_RANGE
);
485 if (myTree
.hasFocus()) {
486 myEditor
.getCaretModel().moveToOffset(start
);
487 myEditor
.getScrollingModel().scrollToCaret(ScrollType
.MAKE_VISIBLE
);
489 myEditor
.getScrollingModel().scrollTo(myEditor
.offsetToLogicalPosition(start
), ScrollType
.MAKE_VISIBLE
);
492 updateReferences(element
);
497 public void updateReferences(PsiElement element
) {
498 final DefaultListModel model
= (DefaultListModel
)myRefs
.getModel();
500 final Object cache
= myRefs
.getClientProperty(REFS_CACHE
);
501 if (cache
instanceof Map
) {
502 ((Map
)cache
).clear();
504 myRefs
.putClientProperty(REFS_CACHE
, new HashMap());
506 if (element
!= null) {
507 for (PsiReference reference
: element
.getReferences()) {
508 model
.addElement(reference
.getClass().getName());
513 private void clearSelection() {
514 myEditor
.getMarkupModel().removeAllHighlighters();
518 public void doCancelAction() {
519 final PsiViewerSettings settings
= PsiViewerSettings
.getSettings();
520 settings
.type
= myPresentation
.getText();
521 settings
.text
= myEditor
.getDocument().getText();
522 settings
.showTreeNodes
= myShowTreeNodesCheckBox
.isSelected();
523 settings
.showWhiteSpaces
= myShowWhiteSpacesBox
.isSelected();
524 final Object selectedDialect
= myDialectsComboBox
.getSelectedItem();
525 settings
.dialect
= myDialectsComboBox
.isVisible() && selectedDialect
!= null ? selectedDialect
.toString() : "";
526 super.doCancelAction();
529 public void dispose() {
530 Disposer
.dispose(myTreeBuilder
);
531 EditorFactory
.getInstance().releaseEditor(myEditor
);
537 private PsiElement
resolve(int index
) {
538 final PsiElement element
= getPsiElement();
539 if (element
== null) return null;
540 Object o
= myRefs
.getClientProperty(REFS_CACHE
);
542 myRefs
.putClientProperty(REFS_CACHE
, o
= new HashMap());
544 HashMap map
= (HashMap
)o
;
545 Object cache
= map
.get(element
);
547 final PsiReference
[] references
= element
.getReferences();
548 cache
= new PsiElement
[references
.length
];
549 for (int i
= 0; i
< references
.length
; i
++) {
550 ((PsiElement
[])cache
)[i
] = references
[i
].resolve();
552 map
.put(element
, cache
);
554 PsiElement
[] elements
= (PsiElement
[])cache
;
555 return index
>= elements
.length ?
null : elements
[index
];
559 public static TreeNode
findNodeWithObject(final Object object
, final TreeModel model
, final Object parent
) {
560 for (int i
= 0; i
< model
.getChildCount(parent
); i
++) {
561 final DefaultMutableTreeNode childNode
= (DefaultMutableTreeNode
) model
.getChild(parent
, i
);
562 if (childNode
.getUserObject().equals(object
)) {
565 final TreeNode node
= findNodeWithObject(object
, model
, childNode
);
566 if (node
!= null) return node
;
572 private class ChoosePsiTypeButton
extends ComboBoxAction
{
573 protected int getMaxRows() {
577 protected int getMinWidth() {
581 protected int getMinHeight() {
586 protected DefaultActionGroup
createPopupActionGroup(JComponent button
) {
591 private class GoToListener
implements KeyListener
, MouseListener
, ListSelectionListener
{
592 private RangeHighlighter myHighlighter
;
593 private final TextAttributes myAttributes
=
594 new TextAttributes(Color
.white
, SELECTION_BG_COLOR
, Color
.red
, EffectType
.BOXED
, Font
.PLAIN
);
596 private void navigate() {
598 final Object value
= myRefs
.getSelectedValue();
599 if (value
instanceof String
) {
600 final String fqn
= (String
)value
;
601 String filename
= fqn
;
602 if (fqn
.contains(".")) {
603 filename
= fqn
.substring(fqn
.lastIndexOf('.') + 1);
605 if (filename
.contains("$")) {
606 filename
= filename
.substring(0, filename
.indexOf('$'));
609 final PsiFile
[] files
= FilenameIndex
.getFilesByName(myProject
, filename
, GlobalSearchScope
.allScope(myProject
));
610 if (files
!= null && files
.length
> 0) {
611 files
[0].navigate(true);
616 public void keyPressed(KeyEvent e
) {
617 if (e
.getKeyCode() == KeyEvent
.VK_ENTER
) {
622 public void mouseClicked(MouseEvent e
) {
623 if (e
.getClickCount() > 1) {
628 public void valueChanged(ListSelectionEvent e
) {
630 updateDialectsCombo();
631 final int ind
= myRefs
.getSelectedIndex();
632 final PsiElement element
= getPsiElement();
633 if (ind
> -1 && element
!= null) {
634 final PsiReference
[] references
= element
.getReferences();
635 if (ind
< references
.length
) {
636 final TextRange textRange
= references
[ind
].getRangeInElement();
637 TextRange range
= element
.getTextRange();
638 int start
= range
.getStartOffset();
639 int end
= range
.getEndOffset();
640 final ViewerTreeStructure treeStructure
= (ViewerTreeStructure
)myTreeBuilder
.getTreeStructure();
641 PsiElement rootPsiElement
= treeStructure
.getRootPsiElement();
642 if (rootPsiElement
!= null) {
643 int baseOffset
= rootPsiElement
.getTextRange().getStartOffset();
648 start
+= textRange
.getStartOffset();
649 end
= start
+ textRange
.getLength();
650 myHighlighter
= myEditor
.getMarkupModel()
651 .addRangeHighlighter(start
, end
, HighlighterLayer
.FIRST
+ 1, myAttributes
, HighlighterTargetArea
.EXACT_RANGE
);
656 public void clearSelection() {
657 if (myHighlighter
!= null && Arrays
.asList(myEditor
.getMarkupModel().getAllHighlighters()).contains(myHighlighter
)) {
658 myEditor
.getMarkupModel().removeHighlighter(myHighlighter
);
659 myHighlighter
= null;
663 public void keyTyped(KeyEvent e
) {}
664 public void keyReleased(KeyEvent e
) {}
665 public void mousePressed(MouseEvent e
) {}
666 public void mouseReleased(MouseEvent e
) {}
667 public void mouseEntered(MouseEvent e
) {}
668 public void mouseExited(MouseEvent e
) {}
671 private class PopupItemAction
extends AnAction
implements DumbAware
{
672 public PopupItemAction(Presentation p
) {
673 super(p
.getText(), p
.getText(), p
.getIcon());
676 public void actionPerformed(AnActionEvent e
) {
677 updatePresentation(e
.getPresentation());
678 updateDialectsCombo();
682 private class EditorListener
implements CaretListener
, SelectionListener
, DocumentListener
{
683 public void caretPositionChanged(CaretEvent e
) {
684 if (!available() || myEditor
.getSelectionModel().hasSelection()) return;
685 final PsiFile psiFile
= getPsiFile();
686 if (psiFile
== null) return;
687 final int offset
= myEditor
.getCaretModel().getOffset();
688 final PsiElement element
= PsiUtilBase
.getElementAtOffset(psiFile
, offset
);
689 myTreeBuilder
.select(element
);
692 public void selectionChanged(SelectionEvent e
) {
693 if (!available() || !myEditor
.getSelectionModel().hasSelection()) return;
694 final PsiFile psiFile
= getPsiFile();
695 if (psiFile
== null) return;
696 final SelectionModel selection
= myEditor
.getSelectionModel();
697 final int start
= selection
.getSelectionStart();
698 final int end
= selection
.getSelectionEnd();
699 final PsiElement element
= findCommonParent(PsiUtilBase
.getElementAtOffset(psiFile
, start
), PsiUtilBase
.getElementAtOffset(psiFile
, end
));
700 myTreeBuilder
.select(element
);
703 private boolean available() {
704 return myLastParsedTextHashCode
== myNewDocumentHashCode
&& myEditor
.getContentComponent().hasFocus();
708 private PsiFile
getPsiFile() {
709 final PsiElement root
= ((ViewerTreeStructure
)myTreeBuilder
.getTreeStructure()).getRootPsiElement();
710 return root
instanceof PsiFile ?
(PsiFile
)root
: null;
713 public void beforeDocumentChange(DocumentEvent event
) {
716 public void documentChanged(DocumentEvent event
) {
717 myNewDocumentHashCode
= event
.getDocument().getText().hashCode();