mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
TextEditorBasedStructureViewModel extracted
This commit is contained in:
@@ -32,5 +32,5 @@
|
||||
package com.intellij.ide.structureView;
|
||||
|
||||
public interface FileEditorPositionListener {
|
||||
void onCurrentElementChanged(Object currentElement);
|
||||
void onCurrentElementChanged();
|
||||
}
|
||||
|
||||
@@ -36,5 +36,11 @@ import com.intellij.ide.util.treeView.smartTree.TreeModel;
|
||||
public interface StructureViewModel extends TreeModel{
|
||||
Object getCurrentEditorElement();
|
||||
|
||||
void addEditorPositionListener(FileEditorPositionListener listener);
|
||||
|
||||
void removeEditorPositionListener(FileEditorPositionListener listener);
|
||||
|
||||
StructureViewTreeElement getRoot();
|
||||
|
||||
void dispose();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* -Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* -Redistribution in binary form must reproduct the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of JetBrains or IntelliJ IDEA
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* This software is provided "AS IS," without a warranty of any kind. ALL
|
||||
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
|
||||
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
|
||||
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT
|
||||
* BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
|
||||
* OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
|
||||
* DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST
|
||||
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
|
||||
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
|
||||
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
|
||||
* IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
*/
|
||||
package com.intellij.ide.structureView;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.event.CaretEvent;
|
||||
import com.intellij.openapi.editor.event.CaretListener;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TextEditorBasedStructureViewModel implements StructureViewModel {
|
||||
private final Editor myEditor;
|
||||
private final CaretListener myCaretListener;
|
||||
private final List<FileEditorPositionListener> myListeners = new ArrayList<FileEditorPositionListener>();
|
||||
|
||||
private static Logger LOG = Logger.getInstance("#com.intellij.ide.structureView.TextEditorBasedStructureViewModel");
|
||||
|
||||
protected TextEditorBasedStructureViewModel(PsiFile psiFile) {
|
||||
this(getEditorForFile(psiFile));
|
||||
|
||||
}
|
||||
|
||||
private static Editor getEditorForFile(final PsiFile psiFile) {
|
||||
final FileEditor[] editors = FileEditorManager.getInstance(psiFile.getProject()).getEditors(psiFile.getVirtualFile());
|
||||
for (int i = 0; i < editors.length; i++) {
|
||||
FileEditor editor = editors[i];
|
||||
if (editor instanceof TextEditor) {
|
||||
return ((TextEditor)editor).getEditor();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected TextEditorBasedStructureViewModel(final Editor editor) {
|
||||
LOG.assertTrue(editor != null);
|
||||
myEditor = editor;
|
||||
myCaretListener = new CaretListener() {
|
||||
public void caretPositionChanged(CaretEvent e) {
|
||||
if (Comparing.equal(e.getEditor(), myEditor)) {
|
||||
fireCaretPositionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void fireCaretPositionChanged() {
|
||||
final FileEditorPositionListener[] listeners = myListeners.toArray(new FileEditorPositionListener[myListeners.size()]);
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
listeners[i].onCurrentElementChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EditorFactory.getInstance().getEventMulticaster().addCaretListener(myCaretListener);
|
||||
}
|
||||
|
||||
public final void addEditorPositionListener(FileEditorPositionListener listener) {
|
||||
myListeners.add(listener);
|
||||
}
|
||||
|
||||
public final void removeEditorPositionListener(FileEditorPositionListener listener) {
|
||||
myListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
EditorFactory.getInstance().getEventMulticaster().removeCaretListener(myCaretListener);
|
||||
}
|
||||
|
||||
public final Object getCurrentEditorElement() {
|
||||
final int offset = myEditor.getCaretModel().getOffset();
|
||||
PsiElement element = getPsiFile().findElementAt(offset);
|
||||
while (!isSutable(element)) {
|
||||
if (element == null) return null;
|
||||
element = element.getParent();
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
protected abstract PsiFile getPsiFile();
|
||||
|
||||
private boolean isSutable(final PsiElement element) {
|
||||
if (element == null) return false;
|
||||
final Class[] suitableClasses = getSuitableClasses();
|
||||
for (int i = 0; i < suitableClasses.length; i++) {
|
||||
Class suitableClass = suitableClasses[i];
|
||||
if (suitableClass.isAssignableFrom(element.getClass())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract Class[] getSuitableClasses();
|
||||
}
|
||||
@@ -78,8 +78,7 @@ public class StructureViewWrapper implements StructureView {
|
||||
}
|
||||
setFileEditor(newEditor);
|
||||
if (myStructureViewFactory.AUTOSCROLL_FROM_SOURCE && myStructureView != null) {
|
||||
FileEditor newEditor = event.getNewEditor();
|
||||
myStructureView.scrollToElementAtCaret(newEditor);
|
||||
myStructureView.scrollToSelectedElement();
|
||||
}
|
||||
}
|
||||
}, 400
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
package com.intellij.ide.structureView.impl.java;
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewModel;
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.TextEditorBasedStructureViewModel;
|
||||
import com.intellij.ide.util.treeView.smartTree.Filter;
|
||||
import com.intellij.ide.util.treeView.smartTree.Grouper;
|
||||
import com.intellij.ide.util.treeView.smartTree.Sorter;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.*;
|
||||
|
||||
public class JavaFileTreeModel implements StructureViewModel {
|
||||
public class JavaFileTreeModel extends TextEditorBasedStructureViewModel {
|
||||
private final PsiJavaFile myFile;
|
||||
|
||||
public JavaFileTreeModel(PsiJavaFile file) {
|
||||
super(file);
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@@ -37,21 +33,11 @@ public class JavaFileTreeModel implements StructureViewModel {
|
||||
return new Sorter[]{KindSorter.INSTANCE, Sorter.ALPHA_SORTER, VisibilitySorter.INSTANCE};
|
||||
}
|
||||
|
||||
public Object getCurrentEditorElement() {
|
||||
final Editor editor = FileEditorManager.getInstance(myFile.getProject()).getSelectedTextEditor();
|
||||
final Document document = FileDocumentManager.getInstance().getDocument(myFile.getVirtualFile());
|
||||
if (!Comparing.equal(editor.getDocument(), document)) return null;
|
||||
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
PsiElement element = myFile.findElementAt(offset);
|
||||
while (!isSutable(element)) {
|
||||
if (element == null) return null;
|
||||
element = element.getParent();
|
||||
}
|
||||
return element;
|
||||
protected PsiFile getPsiFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
private boolean isSutable(final PsiElement element) {
|
||||
return element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiField;
|
||||
protected Class[] getSuitableClasses() {
|
||||
return new Class[]{PsiClass.class, PsiMethod.class, PsiField.class};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,15 +31,20 @@
|
||||
*/
|
||||
package com.intellij.ide.structureView.impl.xml;
|
||||
|
||||
import com.intellij.ide.util.treeView.smartTree.*;
|
||||
import com.intellij.ide.structureView.StructureViewModel;
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.TextEditorBasedStructureViewModel;
|
||||
import com.intellij.ide.util.treeView.smartTree.Filter;
|
||||
import com.intellij.ide.util.treeView.smartTree.Grouper;
|
||||
import com.intellij.ide.util.treeView.smartTree.Sorter;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
|
||||
public class XmlStructureViewTreeModel implements StructureViewModel{
|
||||
public class XmlStructureViewTreeModel extends TextEditorBasedStructureViewModel{
|
||||
private final XmlFile myFile;
|
||||
|
||||
public XmlStructureViewTreeModel(XmlFile file) {
|
||||
super(file);
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
@@ -59,7 +64,11 @@ public class XmlStructureViewTreeModel implements StructureViewModel{
|
||||
return new Filter[0];
|
||||
}
|
||||
|
||||
public Object getCurrentEditorElement() {
|
||||
return null;
|
||||
protected PsiFile getPsiFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
protected Class[] getSuitableClasses() {
|
||||
return new Class[]{XmlTag.class};
|
||||
}
|
||||
}
|
||||
|
||||
+11
-26
@@ -2,6 +2,7 @@ package com.intellij.ide.structureView.newStructureView;
|
||||
|
||||
import com.intellij.ide.CopyPasteManagerEx;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.structureView.FileEditorPositionListener;
|
||||
import com.intellij.ide.structureView.StructureViewFactory;
|
||||
import com.intellij.ide.structureView.StructureViewModel;
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
@@ -13,18 +14,12 @@ import com.intellij.ide.util.treeView.smartTree.*;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.DataConstantsEx;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.event.CaretEvent;
|
||||
import com.intellij.openapi.editor.event.CaretListener;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.ide.CopyPasteManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -382,16 +377,13 @@ public class StructureViewComponent extends JPanel implements TreeActionsOwner,
|
||||
return null;
|
||||
}
|
||||
|
||||
public void scrollToElementAtCaret(final FileEditor editor) {
|
||||
public void scrollToSelectedElement() {
|
||||
if (myAutoscrollFeedback) {
|
||||
myAutoscrollFeedback = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (myFileEditor == null || !Comparing.equal(myFileEditor, editor)) return;
|
||||
|
||||
StructureViewFactoryImpl structureViewFactory
|
||||
= (StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject);
|
||||
StructureViewFactoryImpl structureViewFactory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(myProject);
|
||||
|
||||
if (!structureViewFactory.AUTOSCROLL_FROM_SOURCE) return;
|
||||
|
||||
@@ -512,7 +504,7 @@ public class StructureViewComponent extends JPanel implements TreeActionsOwner,
|
||||
}
|
||||
|
||||
private class MyAutoScrollFromSourceHandler extends AutoScrollFromSourceHandler {
|
||||
private CaretListener myEditorCaretListener;
|
||||
private FileEditorPositionListener myFileEditorPositionListener;
|
||||
|
||||
private MyAutoScrollFromSourceHandler(Project project) {
|
||||
super(project);
|
||||
@@ -523,24 +515,17 @@ public class StructureViewComponent extends JPanel implements TreeActionsOwner,
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
EditorFactory.getInstance().getEventMulticaster().removeCaretListener(myEditorCaretListener);
|
||||
myTreeModel.removeEditorPositionListener(myFileEditorPositionListener);
|
||||
myTreeModel.dispose();
|
||||
}
|
||||
|
||||
private void addEditorCaretListener() {
|
||||
myEditorCaretListener = new CaretListener() {
|
||||
public void caretPositionChanged(final CaretEvent e) {
|
||||
Editor editor = e.getEditor();
|
||||
FileEditor fileEditor = getFileEditorForEditor(editor);
|
||||
scrollToElementAtCaret(fileEditor);
|
||||
}
|
||||
|
||||
private FileEditor getFileEditorForEditor(Editor editor) {
|
||||
VirtualFile file = FileDocumentManager.getInstance().getFile(editor.getDocument());
|
||||
if (file == null) return null;
|
||||
return FileEditorManager.getInstance(myProject).getSelectedEditor(file);
|
||||
myFileEditorPositionListener = new FileEditorPositionListener() {
|
||||
public void onCurrentElementChanged() {
|
||||
scrollToSelectedElement();
|
||||
}
|
||||
};
|
||||
EditorFactory.getInstance().getEventMulticaster().addCaretListener(myEditorCaretListener);
|
||||
myTreeModel.addEditorPositionListener(myFileEditorPositionListener);
|
||||
}
|
||||
|
||||
protected boolean isAutoScrollMode() {
|
||||
@@ -553,7 +538,7 @@ public class StructureViewComponent extends JPanel implements TreeActionsOwner,
|
||||
structureViewFactory.AUTOSCROLL_FROM_SOURCE = state;
|
||||
final FileEditor[] selectedEditors = FileEditorManager.getInstance(myProject).getSelectedEditors();
|
||||
if (selectedEditors != null && selectedEditors.length > 0) {
|
||||
if (state) scrollToElementAtCaret(selectedEditors[0]);
|
||||
if (state) scrollToSelectedElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.intellij.ide.structureView.newStructureView;
|
||||
import com.intellij.ide.util.treeView.smartTree.*;
|
||||
import com.intellij.ide.structureView.StructureViewModel;
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.structureView.FileEditorPositionListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -54,4 +55,16 @@ public class TreeModelWrapper implements StructureViewModel {
|
||||
public static boolean shouldRevert(final TreeAction action) {
|
||||
return action instanceof Filter && ((Filter)action).isReverted();
|
||||
}
|
||||
|
||||
public void addEditorPositionListener(FileEditorPositionListener listener) {
|
||||
myModel.addEditorPositionListener(listener);
|
||||
}
|
||||
|
||||
public void removeEditorPositionListener(FileEditorPositionListener listener) {
|
||||
myModel.removeEditorPositionListener(listener);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
myModel.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.intellij.openapi.util.Comparing;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class CachingChildrenTreeNode <Value> extends AbstractTreeNode<Value> {
|
||||
private List<CachingChildrenTreeNode> myChildren;
|
||||
protected List<CachingChildrenTreeNode> myChildren;
|
||||
protected List<CachingChildrenTreeNode> myOldChildren = null;
|
||||
protected final TreeModel myTreeModel;
|
||||
|
||||
@@ -173,7 +173,7 @@ public abstract class CachingChildrenTreeNode <Value> extends AbstractTreeNode<V
|
||||
}
|
||||
|
||||
protected void synchronizeChildren() {
|
||||
if (myOldChildren != null) {
|
||||
if (myOldChildren != null && myChildren != null) {
|
||||
for (Iterator<CachingChildrenTreeNode> iterator = myOldChildren.iterator(); iterator.hasNext();) {
|
||||
CachingChildrenTreeNode oldInstance = iterator.next();
|
||||
final int newIndex = getIndexOfPointerToTheSameValue(oldInstance);
|
||||
|
||||
@@ -54,6 +54,11 @@ public class SmartTreeStructure extends AbstractTreeStructure {
|
||||
}
|
||||
|
||||
public void rebuildTree() {
|
||||
if (myRootElementWrapper != null) {
|
||||
final TreeElementWrapper newRoot = createTree();
|
||||
newRoot.myOldChildren = myRootElementWrapper.myChildren;
|
||||
newRoot.synchronizeChildren();
|
||||
}
|
||||
((CachingChildrenTreeNode)getRootElement()).rebuildChildren();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user