automatic elements selection

This commit is contained in:
Konstantin Bulenkov
2009-11-13 22:18:14 +03:00
parent 909cfb406b
commit c963b21766
2 changed files with 108 additions and 47 deletions
@@ -24,10 +24,8 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.*;
@@ -46,6 +44,7 @@ import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.ui.SortedComboBoxModel;
import com.intellij.ui.TitledBorderWithMnemonic;
import com.intellij.ui.TreeSpeedSearch;
@@ -61,9 +60,7 @@ import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
@@ -96,6 +93,7 @@ public class PsiViewerDialog extends DialogWrapper {
private Map<String, Object> handlers = new HashMap<String, Object>();
private DefaultActionGroup myGroup;
private Language[] myLanguageDialects;
private final Color SELECTION_BG_COLOR = new Color(0, 51, 51);
private static final Comparator<Language> DIALECTS_COMPARATOR = new Comparator<Language>() {
public int compare(final Language o1, final Language o2) {
if (o1 == null) return o2 == null ? 0 : -1;
@@ -103,6 +101,18 @@ public class PsiViewerDialog extends DialogWrapper {
return o1.getID().compareTo(o2.getID());
}
};
private EditorListener myEditorListener = new EditorListener();
private int myLastParsedTextHashCode = 17;
private int myNewDocumentHashCode = 11;
@Nullable
private static PsiElement findCommonParent(PsiElement start, PsiElement end) {
final TextRange range = end.getTextRange();
while (start != null && !start.getTextRange().contains(range)) {
start = start.getParent();
}
return start;
}
public PsiViewerDialog(Project project, boolean modal) {
super(project, true);
@@ -171,6 +181,9 @@ public class PsiViewerDialog extends DialogWrapper {
final Document document = editorFactory.createDocument("");
myEditor = editorFactory.createEditor(document, myProject);
myEditor.getSettings().setFoldingOutlineShown(false);
document.addDocumentListener(myEditorListener);
myEditor.getSelectionModel().addSelectionListener(myEditorListener);
myEditor.getCaretModel().addCaretListener(myEditorListener);
for (PsiViewerExtension extension : Extensions.getExtensions(PsiViewerExtension.EP_NAME)) {
final Presentation p = new Presentation(extension.getName());
@@ -347,16 +360,18 @@ public class PsiViewerDialog extends DialogWrapper {
@Nullable
private PsiElement getPsiElement() {
TreePath path = myTree.getSelectionPath();
if (path != null) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
if (node.getUserObject() instanceof ViewerNodeDescriptor) {
ViewerNodeDescriptor descriptor = (ViewerNodeDescriptor)node.getUserObject();
Object elementObject = descriptor.getElement();
return elementObject instanceof PsiElement
? (PsiElement)elementObject
: elementObject instanceof ASTNode ? ((ASTNode)elementObject).getPsi() : null;
}
final TreePath path = myTree.getSelectionPath();
return path == null ? null : getPsiElement((DefaultMutableTreeNode)path.getLastPathComponent());
}
@Nullable
private PsiElement getPsiElement(DefaultMutableTreeNode node) {
if (node.getUserObject() instanceof ViewerNodeDescriptor) {
ViewerNodeDescriptor descriptor = (ViewerNodeDescriptor)node.getUserObject();
Object elementObject = descriptor.getElement();
return elementObject instanceof PsiElement
? (PsiElement)elementObject
: elementObject instanceof ASTNode ? ((ASTNode)elementObject).getPsi() : null;
}
return null;
}
@@ -390,6 +405,8 @@ public class PsiViewerDialog extends DialogWrapper {
if (text.trim().length() == 0) return;
myLastParsedText = text;
myLastParsedTextHashCode = text.hashCode();
myNewDocumentHashCode = myLastParsedTextHashCode;
PsiElement rootElement = null;
final Object handler = getHandler();
@@ -430,7 +447,7 @@ public class PsiViewerDialog extends DialogWrapper {
public MyTreeSelectionListener() {
myAttributes = new TextAttributes();
myAttributes.setBackgroundColor(new Color(0, 0, 128));
myAttributes.setBackgroundColor(SELECTION_BG_COLOR);
myAttributes.setForegroundColor(Color.white);
}
@@ -465,8 +482,12 @@ public class PsiViewerDialog extends DialogWrapper {
if (end <= textLength) {
myEditor.getMarkupModel()
.addRangeHighlighter(start, end, HighlighterLayer.FIRST + 1, myAttributes, HighlighterTargetArea.EXACT_RANGE);
myEditor.getCaretModel().moveToOffset(start);
myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
if (myTree.hasFocus()) {
myEditor.getCaretModel().moveToOffset(start);
myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
} else {
myEditor.getScrollingModel().scrollTo(myEditor.offsetToLogicalPosition(start), ScrollType.MAKE_VISIBLE);
}
}
updateReferences(element);
}
@@ -534,6 +555,20 @@ public class PsiViewerDialog extends DialogWrapper {
return index >= elements.length ? null : elements[index];
}
@Nullable
public static TreeNode findNodeWithObject(final Object object, final TreeModel model, final Object parent) {
for (int i = 0; i < model.getChildCount(parent); i++) {
final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) model.getChild(parent, i);
if (childNode.getUserObject().equals(object)) {
return childNode;
} else {
final TreeNode node = findNodeWithObject(object, model, childNode);
if (node != null) return node;
}
}
return null;
}
private class ChoosePsiTypeButton extends ComboBoxAction {
protected int getMaxRows() {
return 15;
@@ -556,7 +591,7 @@ public class PsiViewerDialog extends DialogWrapper {
private class GoToListener implements KeyListener, MouseListener, ListSelectionListener {
private RangeHighlighter myHighlighter;
private final TextAttributes myAttributes =
new TextAttributes(Color.white, new Color(0, 0, 128), Color.red, EffectType.BOXED, Font.PLAIN);
new TextAttributes(Color.white, SELECTION_BG_COLOR, Color.red, EffectType.BOXED, Font.PLAIN);
private void navigate() {
clearSelection();
@@ -625,23 +660,12 @@ public class PsiViewerDialog extends DialogWrapper {
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
private class PopupItemAction extends AnAction implements DumbAware {
@@ -654,4 +678,43 @@ public class PsiViewerDialog extends DialogWrapper {
updateDialectsCombo();
}
}
private class EditorListener implements CaretListener, SelectionListener, DocumentListener {
public void caretPositionChanged(CaretEvent e) {
if (!available() || myEditor.getSelectionModel().hasSelection()) return;
final PsiFile psiFile = getPsiFile();
if (psiFile == null) return;
final int offset = myEditor.getCaretModel().getOffset();
final PsiElement element = PsiUtilBase.getElementAtOffset(psiFile, offset);
myTreeBuilder.select(element);
}
public void selectionChanged(SelectionEvent e) {
if (!available() || !myEditor.getSelectionModel().hasSelection()) return;
final PsiFile psiFile = getPsiFile();
if (psiFile == null) return;
final SelectionModel selection = myEditor.getSelectionModel();
final int start = selection.getSelectionStart();
final int end = selection.getSelectionEnd();
final PsiElement element = findCommonParent(PsiUtilBase.getElementAtOffset(psiFile, start), PsiUtilBase.getElementAtOffset(psiFile, end));
myTreeBuilder.select(element);
}
private boolean available() {
return myLastParsedTextHashCode == myNewDocumentHashCode && myEditor.getContentComponent().hasFocus();
}
@Nullable
private PsiFile getPsiFile() {
final PsiElement root = ((ViewerTreeStructure)myTreeBuilder.getTreeStructure()).getRootPsiElement();
return root instanceof PsiFile ? (PsiFile)root : null;
}
public void beforeDocumentChange(DocumentEvent event) {
}
public void documentChanged(DocumentEvent event) {
myNewDocumentHashCode = event.getDocument().getText().hashCode();
}
}
}
@@ -113,15 +113,13 @@ public class ViewerTreeStructure extends AbstractTreeStructure {
}
public Object getParentElement(Object element) {
return null;
//if (element == myRootElement) {
// return null;
//}
//if (element == myRootPsiElement) {
// return myRootElement;
//}
//PsiElement parent = ((PsiElement)element).getParent();
//return parent;
if (element == myRootElement) {
return null;
}
if (element == myRootPsiElement) {
return myRootElement;
}
return ((PsiElement)element).getParent();
}
public void commit() {