From 894f63ec7084ffebe47b7d8de45c152dc25fa10f Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 30 Jan 2012 12:53:57 +0100 Subject: [PATCH] file structure base test case --- .../ide/actions/ViewStructureAction.java | 2 +- .../intellij/ide/util/FileStructurePopup.java | 85 ++++++++----- .../ide/util/treeView/AbstractTreeUi.java | 18 ++- .../filtered/FilteringTreeBuilder.java | 39 ++++-- .../testFramework/FileStructureTestBase.java | 119 ++++++++++++++++++ 5 files changed, 215 insertions(+), 48 deletions(-) create mode 100644 platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java index a1e115a7f014..4e64b7c3983c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java @@ -90,7 +90,7 @@ public class ViewStructureAction extends AnAction { } @Nullable - private static FileStructurePopup createPopup(final Editor editor, Project project, Navigatable navigatable, final FileEditor fileEditor) { + public static FileStructurePopup createPopup(final Editor editor, Project project, @Nullable Navigatable navigatable, final FileEditor fileEditor) { final StructureViewBuilder structureViewBuilder = fileEditor.getStructureViewBuilder(); if (structureViewBuilder == null) return null; StructureView structureView = structureViewBuilder.createStructureView(fileEditor, project); diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index 2285504fe806..9d885b1e49d8 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -149,6 +149,7 @@ public class FileStructurePopup implements Disposable { myTree = new JBTreeWithHintProvider(new DefaultMutableTreeNode(myTreeStructure.getRootElement())) { @Override protected PsiElement getPsiElementForHint(Object selectedValue) { + //noinspection ConstantConditions return getPsi((FilteringTreeStructure.FilteringNode)((DefaultMutableTreeNode)selectedValue).getUserObject()); } }; @@ -218,12 +219,13 @@ public class FileStructurePopup implements Disposable { return current.isEmpty() ? null : findClosestTo(myInitialPsiElement, current); } + @Nullable private Object findClosestTo(PsiElement path, ArrayList paths) { if (path == null || myInitialPsiElement == null) { return paths.get(0).node; } final Set parents = getAllParents(myInitialPsiElement); - Object cur = paths.get(0).node; + ArrayList cur = new ArrayList(); int max = -1; for (ObjectWithWeight p : paths) { final Object last = ((TreePath)p.node).getLastPathComponent(); @@ -238,14 +240,21 @@ public class FileStructurePopup implements Disposable { final int size = ContainerUtil.intersection(parents, elements).size(); if (size > max) { max = size; - cur = p.node; - } else if (size == max && size == parents.size()) { - cur = p.node; + cur.clear(); + cur.add((TreePath)p.node); + } else if (size == max) { + cur.add((TreePath)p.node); } } } - return cur; + Collections.sort(cur, new Comparator() { + @Override + public int compare(TreePath o1, TreePath o2) { + return o2.getPathCount() - o1.getPathCount(); + } + }); + return cur.isEmpty() ? null : cur.get(0); } class ObjectWithWeight { @@ -285,7 +294,7 @@ public class FileStructurePopup implements Disposable { mySpeedSearch.setComparator(new SpeedSearchComparator(false, true)); final FileStructurePopupFilter filter = new FileStructurePopupFilter(); - myFilteringStructure = new FilteringTreeStructure(filter, myTreeStructure, false); + myFilteringStructure = new FilteringTreeStructure(filter, myTreeStructure, ApplicationManager.getApplication().isUnitTestMode()); myAbstractTreeBuilder = new FilteringTreeBuilder(myTree, filter, myFilteringStructure, null) { @Override protected boolean validateNode(Object child) { @@ -385,35 +394,37 @@ public class FileStructurePopup implements Disposable { }); } }); - final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myPopup); - alarm.addRequest(new Runnable() { - String filter = ""; + if (!ApplicationManager.getApplication().isUnitTestMode()) { + final Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myPopup); + alarm.addRequest(new Runnable() { + String filter = ""; - @Override - public void run() { - alarm.cancelAllRequests(); - String prefix = mySpeedSearch.getEnteredPrefix(); - myTree.getEmptyText().setText(StringUtil.isEmpty(prefix) ? "Nothing to show" : "Can't find '" + prefix + "'"); - if (prefix == null) prefix = ""; + @Override + public void run() { + alarm.cancelAllRequests(); + String prefix = mySpeedSearch.getEnteredPrefix(); + myTree.getEmptyText().setText(StringUtil.isEmpty(prefix) ? "Nothing to show" : "Can't find '" + prefix + "'"); + if (prefix == null) prefix = ""; - if (!filter.equals(prefix)) { - filter = prefix; - myAbstractTreeBuilder.refilter(null, false, false).doWhenProcessed(new Runnable() { - @Override - public void run() { - myTree.repaint(); - //if (mySpeedSearch.isPopupActive()) { - // mySpeedSearch.refreshSelection(); - //} - } - }); + if (!filter.equals(prefix)) { + filter = prefix; + myAbstractTreeBuilder.refilter(null, false, false).doWhenProcessed(new Runnable() { + @Override + public void run() { + myTree.repaint(); + //if (mySpeedSearch.isPopupActive()) { + // mySpeedSearch.refreshSelection(); + //} + } + }); + } + alarm.addRequest(this, 300); } - alarm.addRequest(this, 300); - } - }, 300); + }, 300); + } } - private void selectPsiElement(PsiElement element) { + public void selectPsiElement(PsiElement element) { Set parents = getAllParents(element); FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)myAbstractTreeBuilder.getRootElement(); @@ -478,7 +489,7 @@ public class FileStructurePopup implements Disposable { } @Nullable - protected PsiElement getCurrentElement(@Nullable final PsiFile psiFile) { + public PsiElement getCurrentElement(@Nullable final PsiFile psiFile) { if (psiFile == null) return null; PsiDocumentManager.getInstance(myProject).commitAllDocuments(); @@ -718,6 +729,18 @@ public class FileStructurePopup implements Disposable { myTitle = title; } + public Tree getTree() { + return myTree; + } + + public TreeSpeedSearch getSpeedSearch() { + return mySpeedSearch; + } + + public FilteringTreeBuilder getTreeBuilder() { + return myAbstractTreeBuilder; + } + private class FileStructurePopupFilter implements ElementFilter { private String myLastFilter = null; private HashSet myVisibleParents = new HashSet(); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index ced3ab62d05d..43423a359932 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -2362,7 +2362,7 @@ public class AbstractTreeUi { final ActionCallback done = new ActionCallback(); - invokeLaterIfNeeded(new Runnable() { + final Runnable cancelUpdate = new Runnable() { public void run() { if (isReleased()) { done.setRejected(); @@ -2371,21 +2371,29 @@ public class AbstractTreeUi { if (myResettingToReadyNow.get()) { _getReady().notify(done); - } else if (isReady()) { + } + else if (isReady()) { resetToReadyNow(); done.setDone(); - } else { + } + else { if (isIdle() && hasPendingWork()) { resetToReadyNow(); done.setDone(); - } else { + } + else { _getReady().notify(done); } } maybeReady(); } - }, false); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + cancelUpdate.run(); + } else { + invokeLaterIfNeeded(cancelUpdate, false); + } if (isEdt() || isPassthroughMode()) { maybeReady(); diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java index 941dafef44eb..71f152e5fc58 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeBuilder.java @@ -18,6 +18,7 @@ package com.intellij.ui.treeStructure.filtered; import com.intellij.ide.util.treeView.AbstractTreeBuilder; import com.intellij.ide.util.treeView.AbstractTreeStructure; import com.intellij.ide.util.treeView.NodeDescriptor; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Disposer; import com.intellij.ui.speedSearch.ElementFilter; @@ -120,7 +121,7 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { myRefilterQueue.cancelAllUpdates(); } final ActionCallback callback = new ActionCallback(); - getUi().cancelUpdate().doWhenProcessed(new Runnable() { + final Runnable afterCancelUpdate = new Runnable() { @Override public void run() { if (myRefilterQueue == null || now) { @@ -145,7 +146,12 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { }); } } - }); + }; + if (!ApplicationManager.getApplication().isUnitTestMode()) { + getUi().cancelUpdate().doWhenProcessed(afterCancelUpdate); + } else { + afterCancelUpdate.run(); + } return callback; } @@ -155,7 +161,7 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { final ActionCallback selectionDone = new ActionCallback(); getFilteredStructure().refilter(); - queueUpdate().doWhenProcessed(new Runnable() { + final Runnable selectionRunnable = new Runnable() { public void run() { revalidateTree(); @@ -173,25 +179,36 @@ public class FilteringTreeBuilder extends AbstractTreeBuilder { selectionDone.setDone(); } }); - } else { + } + else { TreeUtil.ensureSelection(myTree); selectionDone.setDone(); } - } else { + } + else { selectionDone.setDone(); } } - }); + }; + if (!ApplicationManager.getApplication().isUnitTestMode()) { + queueUpdate().doWhenProcessed(selectionRunnable); + } else { + selectionRunnable.run(); + } final ActionCallback result = new ActionCallback(); selectionDone.doWhenDone(new Runnable() { public void run() { - scrollSelectionToVisible(new Runnable() { - public void run() { - getReady(this).notify(result); - } - }, false); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + scrollSelectionToVisible(new Runnable() { + public void run() { + getReady(this).notify(result); + } + }, false); + } else { + result.setDone(); + } } }).doWhenRejected(new Runnable() { @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java new file mode 100644 index 000000000000..3f991b0cb683 --- /dev/null +++ b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.testFramework; + +import com.intellij.ide.actions.ViewStructureAction; +import com.intellij.ide.util.FileStructurePopup; +import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; +import com.intellij.ui.TreeSpeedSearch; +import com.intellij.ui.treeStructure.Tree; +import com.intellij.ui.treeStructure.filtered.FilteringTreeBuilder; +import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure; +import com.intellij.util.ui.tree.TreeUtil; +import junit.framework.Assert; +import org.junit.Before; + +import java.io.File; + +/** + * @author Konstantin Bulenkov + */ +public abstract class FileStructureTestBase extends CodeInsightFixtureTestCase { + FileStructurePopup myPopup; + + @Before + public void setUp() throws Exception { + super.setUp(); + myFixture.configureByFile(getFileName(getFileExtension())); + myPopup = ViewStructureAction.createPopup(myFixture.getEditor(), + myFixture.getProject(), + null, + TextEditorProvider.getInstance().getTextEditor(myFixture.getEditor())); + update(); + } + + protected abstract String getFileExtension(); + + @Override + public void tearDown() throws Exception { + Disposer.dispose(myPopup); + super.tearDown(); + } + + private String getFileName(String ext) { + return getTestName(false) + (StringUtil.isEmpty(ext) ? "" : "." + ext); + } + + protected String getTreeFileName() { + return getFileName("tree"); + } + + protected void checkTree() throws Exception { + final String expected = FileUtil.loadFile(new File(getTestDataPath() + "/" + getTreeFileName())); + Assert.assertEquals(expected, PlatformTestUtil.print(getTree(), true)); + } + + + private void update() throws InterruptedException { + myPopup.getTreeBuilder().refilter().doWhenProcessed(new Runnable() { + @Override + public void run() { + getStructure().rebuild(); + updateTree(); + TreeUtil.expandAll(getTree()); + myPopup.selectPsiElement(getFile()); + } + }); + } + + protected Tree getTree() { + return myPopup.getTree(); + } + + protected FilteringTreeBuilder getBuilder() { + return myPopup.getTreeBuilder(); + } + + protected TreeSpeedSearch getSpeedSearch() { + return myPopup.getSpeedSearch(); + } + + + protected void updateTree() { + updateRecursively(getRootNode()); + } + + protected FilteringTreeStructure getStructure() { + final FilteringTreeStructure structure = (FilteringTreeStructure)getBuilder().getTreeStructure(); + assert structure != null; + return structure; + } + + protected FilteringTreeStructure.FilteringNode getRootNode() { + return (FilteringTreeStructure.FilteringNode)getStructure().getRootElement(); + } + + protected void updateRecursively(final FilteringTreeStructure.FilteringNode node) { + node.update(); + for (FilteringTreeStructure.FilteringNode child : node.children()) { + updateRecursively(child); + } + } +}