automatic elements selection
[fedora-idea.git] / platform / lang-impl / src / com / intellij / internal / psiView / PsiViewerDialog.java
blob16ef431fa7065ea176ed89f6c7a46c80bb2a69e4
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.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;
58 import javax.swing.*;
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.*;
64 import java.awt.*;
65 import java.awt.event.*;
66 import java.util.*;
67 import java.util.List;
69 /**
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;
108 @Nullable
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();
114 return start;
117 public PsiViewerDialog(Project project, boolean modal) {
118 super(project, true);
119 setTitle("PSI Viewer");
120 myProject = project;
121 myTree = new Tree(new DefaultTreeModel(new DefaultMutableTreeNode()));
122 UIUtil.setLineStyleAngled(myTree);
123 myTree.setRootVisible(false);
124 myTree.setShowsRootHandles(true);
125 myTree.updateUI();
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);
155 return comp;
159 setModal(modal);
160 setOKButtonText("&Build PSI Tree");
161 init();
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() {
178 initBorders();
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);
192 items.add(p);
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);
209 items.add(p);
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);
246 break;
250 ApplicationManager.getApplication().runWriteAction(new Runnable() {
251 public void run() {
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);
267 break;
272 registerCustomKeyboardActions();
273 super.init();
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) {
285 jButton.doClick();
287 }, KeyStroke.getKeyStroke(KeyEvent.VK_P, mask));
289 registerKeyboardAction(new ActionListener() {
290 public void actionPerformed(ActionEvent e) {
291 focusEditor();
293 }, KeyStroke.getKeyStroke(KeyEvent.VK_T, mask));
295 registerKeyboardAction(new ActionListener() {
296 public void actionPerformed(ActionEvent e) {
297 focusTree();
299 }, KeyStroke.getKeyStroke(KeyEvent.VK_S, mask));
301 registerKeyboardAction(new ActionListener() {
302 public void actionPerformed(ActionEvent e) {
303 focusTree();
305 }, KeyStroke.getKeyStroke(KeyEvent.VK_S, mask));
308 registerKeyboardAction(new ActionListener() {
309 public void actionPerformed(ActionEvent e) {
310 focusTree();
312 }, KeyStroke.getKeyStroke(KeyEvent.VK_S, mask));
314 registerKeyboardAction(new ActionListener() {
315 public void actionPerformed(ActionEvent e) {
316 focusRefs();
318 }, KeyStroke.getKeyStroke(KeyEvent.VK_R, mask));
320 registerKeyboardAction(new ActionListener() {
321 public void actionPerformed(ActionEvent e) {
322 if (myRefs.isFocusOwner()) {
323 focusTree();
325 else if (myTree.isFocusOwner()) {
326 focusRefs();
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"));
361 @Nullable
362 private PsiElement getPsiElement() {
363 final TreePath path = myTree.getSelectionPath();
364 return path == null ? null : getPsiElement((DefaultMutableTreeNode)path.getLastPathComponent());
367 @Nullable
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;
376 return 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() {
396 return myPanel;
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();
413 try {
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);
426 else {
427 rootElement = PsiFileFactory.getInstance(myProject).createFileFromText("Dummy." + type.getDefaultExtension(), text);
430 focusTree();
432 catch (IncorrectOperationException e1) {
433 rootElement = null;
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);
441 myTree.expandRow(0);
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();
457 if (path == null) {
458 clearSelection();
460 else {
461 clearSelection();
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();
477 start -= baseOffset;
478 end -= baseOffset;
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);
488 } else {
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();
499 model.clear();
500 final Object cache = myRefs.getClientProperty(REFS_CACHE);
501 if (cache instanceof Map) {
502 ((Map)cache).clear();
503 } else {
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);
533 super.dispose();
536 @Nullable
537 private PsiElement resolve(int index) {
538 final PsiElement element = getPsiElement();
539 if (element == null) return null;
540 Object o = myRefs.getClientProperty(REFS_CACHE);
541 if (o == null) {
542 myRefs.putClientProperty(REFS_CACHE, o = new HashMap());
544 HashMap map = (HashMap)o;
545 Object cache = map.get(element);
546 if (cache == null) {
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];
558 @Nullable
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)) {
563 return childNode;
564 } else {
565 final TreeNode node = findNodeWithObject(object, model, childNode);
566 if (node != null) return node;
569 return null;
572 private class ChoosePsiTypeButton extends ComboBoxAction {
573 protected int getMaxRows() {
574 return 15;
577 protected int getMinWidth() {
578 return 150;
581 protected int getMinHeight() {
582 return 200;
585 @NotNull
586 protected DefaultActionGroup createPopupActionGroup(JComponent button) {
587 return myGroup;
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() {
597 clearSelection();
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('$'));
608 filename += ".java";
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) {
618 navigate();
622 public void mouseClicked(MouseEvent e) {
623 if (e.getClickCount() > 1) {
624 navigate();
628 public void valueChanged(ListSelectionEvent e) {
629 clearSelection();
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();
644 start -= baseOffset;
645 end -= baseOffset;
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();
707 @Nullable
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();