summaryrefslogtreecommitdiff
path: root/designer
diff options
context:
space:
mode:
authorJens Ole Lauridsen <jlauridsen@google.com>2015-07-08 10:00:17 -0700
committerDeepanshu Gupta <deepanshu@google.com>2015-07-13 17:39:16 -0700
commit2a26b3683dd1180a4343415945714eaa012350e4 (patch)
tree28676f075c29d2e506932a72c4e0777cd8ee926d /designer
parent31f5ff1614f1ed9afe3fd43619940d81a82c59c5 (diff)
downloadidea-2a26b3683dd1180a4343415945714eaa012350e4.tar.gz
Nele: Create component tree (pure restructure).
As a preparation for adding drag and drop to the structure pane, create a class for controlling the tree separate from the structure pane that also controls the properties panel. Change-Id: I8696eefce9a56bc087ae6140ba609601f03f3371 (cherry picked from commit 6879840782a434d166924d9f48b04da257ccc1a1)
Diffstat (limited to 'designer')
-rw-r--r--designer/src/com/android/tools/idea/uibuilder/structure/NlComponentTree.java336
-rw-r--r--designer/src/com/android/tools/idea/uibuilder/structure/NlStructurePanel.java314
-rw-r--r--designer/testSrc/com/android/tools/idea/uibuilder/structure/NlComponentTreeTest.java (renamed from designer/testSrc/com/android/tools/idea/uibuilder/structure/NlStructurePanelTest.java)27
3 files changed, 355 insertions, 322 deletions
diff --git a/designer/src/com/android/tools/idea/uibuilder/structure/NlComponentTree.java b/designer/src/com/android/tools/idea/uibuilder/structure/NlComponentTree.java
new file mode 100644
index 00000000000..b28d470dff8
--- /dev/null
+++ b/designer/src/com/android/tools/idea/uibuilder/structure/NlComponentTree.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.android.tools.idea.uibuilder.structure;
+
+import com.android.SdkConstants;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.tools.idea.uibuilder.model.*;
+import com.android.tools.idea.uibuilder.surface.DesignSurface;
+import com.android.tools.idea.uibuilder.surface.DesignSurfaceListener;
+import com.android.tools.idea.uibuilder.surface.ScreenView;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.ui.ColoredTreeCellRenderer;
+import com.intellij.ui.treeStructure.Tree;
+import com.intellij.util.IJSwingUtilities;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.util.ui.update.MergingUpdateQueue;
+import com.intellij.util.ui.update.Update;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+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.TreeSelectionModel;
+import java.awt.Insets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static com.android.SdkConstants.*;
+import static com.android.tools.idea.uibuilder.property.NlPropertiesPanel.UPDATE_DELAY_MSECS;
+import static com.intellij.util.Alarm.ThreadToUse.SWING_THREAD;
+
+public class NlComponentTree extends Tree implements Disposable, DesignSurfaceListener, ModelListener, SelectionListener {
+ private static final Insets INSETS = new Insets(0, 6, 0, 6);
+
+ private final StructureTreeDecorator myDecorator;
+ private final Map<XmlTag, DefaultMutableTreeNode> myTag2Node;
+ private final AtomicBoolean mySelectionIsUpdating;
+ private final MergingUpdateQueue myUpdateQueue;
+
+ private NlModel myModel;
+ private boolean myWasExpanded;
+
+ public NlComponentTree() {
+ myDecorator = StructureTreeDecorator.get();
+ myTag2Node = new HashMap<XmlTag, DefaultMutableTreeNode>();
+ mySelectionIsUpdating = new AtomicBoolean(false);
+ myUpdateQueue = new MergingUpdateQueue("android.layout.structure-pane", UPDATE_DELAY_MSECS, true, null, this, null, SWING_THREAD);
+ DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(null);
+ DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
+ setModel(treeModel);
+ getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
+ setBorder(new EmptyBorder(INSETS));
+ setRootVisible(false);
+ setShowsRootHandles(false);
+ setToggleClickCount(1);
+ ToolTipManager.sharedInstance().registerComponent(this);
+ TreeUtil.installActions(this);
+ createCellRenderer();
+ addTreeSelectionListener(new StructurePaneSelectionListener());
+//todo: new StructureSpeedSearch(myTree);
+//todo: enableDnD(myTree);
+ }
+
+ public void setDesignSurface(@Nullable DesignSurface designSurface) {
+ setModel(designSurface != null && designSurface.getCurrentScreenView() != null ? designSurface.getCurrentScreenView().getModel() : null);
+ }
+
+ private void setModel(@Nullable NlModel model) {
+ if (myModel != null) {
+ myModel.removeListener(this);
+ myModel.getSelectionModel().removeListener(this);
+ }
+ myModel = model;
+ if (myModel != null) {
+ myModel.addListener(this);
+ myModel.getSelectionModel().addListener(this);
+ }
+ loadData();
+ }
+
+ @Override
+ public void dispose() {
+ if (myModel != null) {
+ myModel.removeListener(this);
+ myModel.getSelectionModel().removeListener(this);
+ }
+ }
+
+ private void createCellRenderer() {
+ setCellRenderer(new ColoredTreeCellRenderer() {
+ @Override
+ public void customizeCellRenderer(@NonNull JTree tree,
+ Object value,
+ boolean selected,
+ boolean expanded,
+ boolean leaf,
+ int row,
+ boolean hasFocus) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
+ NlComponent component = (NlComponent)node.getUserObject();
+ if (component == null) {
+ return;
+ }
+ myDecorator.decorate(component, this, true);
+ }
+ });
+ }
+
+ private void loadData() {
+ updateHierarchy(true);
+ }
+
+ private void invalidateUI() {
+ IJSwingUtilities.updateComponentTreeUI(this);
+ }
+
+ private void updateHierarchy(final boolean firstLoad) {
+ ApplicationManager.getApplication().assertIsDispatchThread();
+ setPaintBusy(true);
+ myUpdateQueue.queue(new Update("updateComponentStructure") {
+ @Override
+ public void run() {
+ try {
+ mySelectionIsUpdating.set(true);
+ if (firstLoad) {
+ myWasExpanded = false;
+ myTag2Node.clear();
+ }
+ DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)getModel().getRoot();
+ List<NlComponent> components = myModel != null ? myModel.getComponents() : null;
+ replaceChildNodes(rootNode, components);
+ expandOnce();
+ invalidateUI();
+ } finally {
+ setPaintBusy(false);
+ mySelectionIsUpdating.set(false);
+ }
+ if (firstLoad) {
+ updateSelection();
+ }
+ }
+ });
+ }
+
+ private void replaceChildNodes(@NonNull DefaultMutableTreeNode node, @Nullable List<NlComponent> subComponents) {
+ node.removeAllChildren();
+ if (subComponents != null) {
+ for (NlComponent child : subComponents) {
+ node.add(makeNode(child));
+ }
+ }
+ }
+
+ @NonNull
+ private DefaultMutableTreeNode makeNode(@NonNull NlComponent component) {
+ DefaultMutableTreeNode node = myTag2Node.get(component.getTag());
+ if (node == null) {
+ node = new DefaultMutableTreeNode(component);
+ myTag2Node.put(component.getTag(), node);
+ } else {
+ node.setUserObject(component);
+ }
+ replaceChildNodes(node, component.children);
+ return node;
+ }
+
+ private void expandOnce() {
+ if (myWasExpanded) {
+ return;
+ }
+ final DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)getModel().getRoot();
+ if (rootNode.isLeaf()) {
+ return;
+ }
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ DefaultMutableTreeNode nodeToExpand = rootNode;
+ NlComponent component = findComponentToExpandTo();
+ if (component != null) {
+ nodeToExpand = myTag2Node.get(component.getTag());
+ if (nodeToExpand == null) {
+ nodeToExpand = rootNode;
+ }
+ }
+ TreePath path = new TreePath(nodeToExpand.getPath());
+ expandPath(path);
+ while (path != null) {
+ path = path.getParentPath();
+ expandPath(path);
+ }
+ myWasExpanded = true;
+ }
+ });
+ }
+
+ // Find a component that it would be interesting to expand to when a new file is viewed.
+ // If the file has an App Bar lookup something that may be user content.
+ @Nullable
+ private NlComponent findComponentToExpandTo() {
+ if (myModel == null || myModel.getComponents().isEmpty()) {
+ return null;
+ }
+ NlComponent root = myModel.getComponents().get(0);
+ NlComponent childOfInterest = root;
+ if (root.getTagName().equals(COORDINATOR_LAYOUT)) {
+ // Find first child that is not an AppBarLayout and not anchored to anything.
+ for (NlComponent child : root.getChildren()) {
+ if (!child.getTagName().equals(APP_BAR_LAYOUT) &&
+ child.getTag().getAttribute(ATTR_LAYOUT_ANCHOR, AUTO_URI) == null) {
+ // If this is a NestedScrollView look inside:
+ if (child.getTagName().equals(SdkConstants.CLASS_NESTED_SCROLL_VIEW) && child.children != null && !child.children.isEmpty()) {
+ child = child.getChild(0);
+ }
+ childOfInterest = child;
+ break;
+ }
+ }
+ }
+
+ if (childOfInterest == null || childOfInterest.children == null || childOfInterest.children.isEmpty()) {
+ return childOfInterest;
+ }
+ return childOfInterest.children.get(childOfInterest.children.size() - 1);
+ }
+
+ private void updateSelection() {
+ if (!mySelectionIsUpdating.compareAndSet(false, true)) {
+ return;
+ }
+ try {
+ clearSelection();
+ if (myModel != null) {
+ for (NlComponent component : myModel.getSelectionModel().getSelection()) {
+ DefaultMutableTreeNode node = myTag2Node.get(component.getTag());
+ if (node != null) {
+ TreePath path = new TreePath(node.getPath());
+ expandPath(path);
+ addSelectionPath(path);
+ }
+ }
+ }
+ } finally {
+ mySelectionIsUpdating.set(false);
+ }
+ }
+
+ // ---- Implemented SelectionListener ----
+ @Override
+ public void selectionChanged(@NonNull SelectionModel model, @NonNull List<NlComponent> selection) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ updateSelection();
+ }
+ });
+ }
+
+ // ---- Implemented ModelListener ----
+ @Override
+ public void modelChanged(@NonNull NlModel model) {
+ }
+
+ @Override
+ public void modelRendered(@NonNull NlModel model) {
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ updateHierarchy(false);
+ }
+ });
+ }
+
+ // ---- Implemented DesignSurfaceListener ----
+
+ @Override
+ public void componentSelectionChanged(@NonNull DesignSurface surface, @NonNull List<NlComponent> newSelection) {
+ }
+
+ @Override
+ public void screenChanged(@NonNull DesignSurface surface, @Nullable ScreenView screenView) {
+ setModel(screenView != null ? screenView.getModel() : null);
+ }
+
+ @Override
+ public void modelChanged(@NonNull DesignSurface surface, @Nullable NlModel model) {
+ if (model != null) {
+ modelRendered(model);
+ }
+ }
+
+ private class StructurePaneSelectionListener implements TreeSelectionListener {
+ @Override
+ public void valueChanged(TreeSelectionEvent treeSelectionEvent) {
+ if (!mySelectionIsUpdating.compareAndSet(false, true)) {
+ return;
+ }
+ try {
+ List<NlComponent> selected = new ArrayList<NlComponent>();
+ TreePath[] paths = getSelectionPaths();
+ if (paths != null) {
+ for (TreePath path : paths) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
+ selected.add((NlComponent)node.getUserObject());
+ }
+ }
+ myModel.getSelectionModel().setSelection(selected);
+ } finally {
+ mySelectionIsUpdating.set(false);
+ }
+ }
+ }
+}
diff --git a/designer/src/com/android/tools/idea/uibuilder/structure/NlStructurePanel.java b/designer/src/com/android/tools/idea/uibuilder/structure/NlStructurePanel.java
index fc91009ec97..23b31c81490 100644
--- a/designer/src/com/android/tools/idea/uibuilder/structure/NlStructurePanel.java
+++ b/designer/src/com/android/tools/idea/uibuilder/structure/NlStructurePanel.java
@@ -15,97 +15,40 @@
*/
package com.android.tools.idea.uibuilder.structure;
-import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
-import com.android.tools.idea.uibuilder.model.*;
import com.android.tools.idea.uibuilder.property.NlPropertiesPanel;
import com.android.tools.idea.uibuilder.surface.DesignSurface;
-import com.android.tools.idea.uibuilder.surface.DesignSurfaceListener;
-import com.android.tools.idea.uibuilder.surface.ScreenView;
import com.intellij.designer.LightToolWindowContent;
-import com.intellij.ide.dnd.aware.DnDAwareTree;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.Splitter;
-import com.intellij.psi.xml.XmlTag;
-import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.ScrollPaneFactory;
-import com.intellij.util.IJSwingUtilities;
-import com.intellij.util.ui.UIUtil;
-import com.intellij.util.ui.tree.TreeUtil;
-import com.intellij.util.ui.update.MergingUpdateQueue;
-import com.intellij.util.ui.update.Update;
import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-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.TreeSelectionModel;
import java.awt.*;
-import java.awt.Insets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import static com.android.SdkConstants.*;
-import static com.android.tools.idea.uibuilder.property.NlPropertiesPanel.UPDATE_DELAY_MSECS;
-import static com.intellij.util.Alarm.ThreadToUse.SWING_THREAD;
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
-public class NlStructurePanel extends JPanel implements LightToolWindowContent, DesignSurfaceListener, ModelListener, SelectionListener {
- private static final Insets INSETS = new Insets(0, 6, 0, 6);
-
- private final DnDAwareTree myTree;
- private final StructureTreeDecorator myDecorator;
- private final Map<XmlTag, DefaultMutableTreeNode> myTag2Node;
- private final AtomicBoolean mySelectionIsUpdating;
+public class NlStructurePanel extends JPanel implements LightToolWindowContent {
+ private final NlComponentTree myTree;
private final NlPropertiesPanel myPropertiesPanel;
- private final MergingUpdateQueue myUpdateQueue;
-
- private NlModel myModel;
- private boolean myWasExpanded;
public NlStructurePanel(@NonNull DesignSurface designSurface) {
- myDecorator = StructureTreeDecorator.get();
- myTree = new DnDAwareTree();
- myTag2Node = new HashMap<XmlTag, DefaultMutableTreeNode>();
- mySelectionIsUpdating = new AtomicBoolean(false);
+ myTree = new NlComponentTree();
JScrollPane pane = ScrollPaneFactory.createScrollPane(myTree, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER);
myPropertiesPanel = new NlPropertiesPanel(designSurface);
- myUpdateQueue = new MergingUpdateQueue(
- "android.layout.structure-pane", UPDATE_DELAY_MSECS, true, null, designSurface, null, SWING_THREAD);
Splitter splitter = new Splitter(true, 0.4f);
splitter.setFirstComponent(pane);
splitter.setSecondComponent(myPropertiesPanel);
- initTree();
setLayout(new BorderLayout());
add(splitter, BorderLayout.CENTER);
setDesignSurface(designSurface);
}
public void setDesignSurface(@Nullable DesignSurface designSurface) {
+ myTree.setDesignSurface(designSurface);
myPropertiesPanel.setDesignSurface(designSurface);
- setModel(designSurface != null && designSurface.getCurrentScreenView() != null ? designSurface.getCurrentScreenView().getModel() : null);
- }
-
- private void setModel(@Nullable NlModel model) {
- if (myModel != null) {
- myModel.removeListener(this);
- myModel.getSelectionModel().removeListener(this);
- }
- myModel = model;
- if (myModel != null) {
- myModel.addListener(this);
- myModel.getSelectionModel().addListener(this);
- }
- loadData();
}
public JComponent getPanel() {
@@ -114,256 +57,11 @@ public class NlStructurePanel extends JPanel implements LightToolWindowContent,
@Override
public void dispose() {
- if (myModel != null) {
- myModel.removeListener(this);
- myModel.getSelectionModel().removeListener(this);
- }
+ myTree.dispose();
}
@VisibleForTesting
- JTree getTree() {
+ JTree getTree2() {
return myTree;
}
-
- private void initTree() {
- DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(null);
- DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
- myTree.setModel(treeModel);
- myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
- myTree.setBorder(new EmptyBorder(INSETS));
- myTree.setRootVisible(false);
- myTree.setShowsRootHandles(false);
- myTree.setToggleClickCount(1);
- ToolTipManager.sharedInstance().registerComponent(myTree);
- TreeUtil.installActions(myTree);
- createCellRenderer(myTree);
- myTree.addTreeSelectionListener(new StructurePaneSelectionListener());
-//todo: new StructureSpeedSearch(myTree);
-//todo: enableDnD(myTree);
- }
-
- private void createCellRenderer(@NonNull JTree tree) {
- tree.setCellRenderer(new ColoredTreeCellRenderer() {
- @Override
- public void customizeCellRenderer(@NonNull JTree tree,
- Object value,
- boolean selected,
- boolean expanded,
- boolean leaf,
- int row,
- boolean hasFocus) {
- DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
- NlComponent component = (NlComponent)node.getUserObject();
- if (component == null) {
- return;
- }
- myDecorator.decorate(component, this, true);
- }
- });
- }
-
- private void loadData() {
- updateHierarchy(true);
- }
-
- private void invalidateUI() {
- IJSwingUtilities.updateComponentTreeUI(myTree);
- }
-
- private void updateHierarchy(final boolean firstLoad) {
- ApplicationManager.getApplication().assertIsDispatchThread();
- myTree.setPaintBusy(true);
- myUpdateQueue.queue(new Update("updateComponentStructure") {
- @Override
- public void run() {
- try {
- mySelectionIsUpdating.set(true);
- if (firstLoad) {
- myWasExpanded = false;
- myTag2Node.clear();
- }
- DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)myTree.getModel().getRoot();
- List<NlComponent> components = myModel != null ? myModel.getComponents() : null;
- replaceChildNodes(rootNode, components);
- expandOnce();
- invalidateUI();
- } finally {
- myTree.setPaintBusy(false);
- mySelectionIsUpdating.set(false);
- }
- if (firstLoad) {
- updateSelection();
- }
- }
- });
- }
-
- private void replaceChildNodes(@NonNull DefaultMutableTreeNode node, @Nullable List<NlComponent> subComponents) {
- node.removeAllChildren();
- if (subComponents != null) {
- for (NlComponent child : subComponents) {
- node.add(makeNode(child));
- }
- }
- }
-
- @NonNull
- private DefaultMutableTreeNode makeNode(@NonNull NlComponent component) {
- DefaultMutableTreeNode node = myTag2Node.get(component.getTag());
- if (node == null) {
- node = new DefaultMutableTreeNode(component);
- myTag2Node.put(component.getTag(), node);
- } else {
- node.setUserObject(component);
- }
- replaceChildNodes(node, component.children);
- return node;
- }
-
- private void expandOnce() {
- if (myWasExpanded) {
- return;
- }
- final DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode)myTree.getModel().getRoot();
- if (rootNode.isLeaf()) {
- return;
- }
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- DefaultMutableTreeNode nodeToExpand = rootNode;
- NlComponent component = findComponentToExpandTo();
- if (component != null) {
- nodeToExpand = myTag2Node.get(component.getTag());
- if (nodeToExpand == null) {
- nodeToExpand = rootNode;
- }
- }
- TreePath path = new TreePath(nodeToExpand.getPath());
- myTree.expandPath(path);
- while (path != null) {
- path = path.getParentPath();
- myTree.expandPath(path);
- }
- myWasExpanded = true;
- }
- });
- }
-
- // Find a component that it would be interesting to expand to when a new file is viewed.
- // If the file has an App Bar lookup something that may be user content.
- @Nullable
- private NlComponent findComponentToExpandTo() {
- if (myModel == null || myModel.getComponents().isEmpty()) {
- return null;
- }
- NlComponent root = myModel.getComponents().get(0);
- NlComponent childOfInterest = root;
- if (root.getTagName().equals(COORDINATOR_LAYOUT)) {
- // Find first child that is not an AppBarLayout and not anchored to anything.
- for (NlComponent child : root.getChildren()) {
- if (!child.getTagName().equals(APP_BAR_LAYOUT) &&
- child.getTag().getAttribute(ATTR_LAYOUT_ANCHOR, AUTO_URI) == null) {
- // If this is a NestedScrollView look inside:
- if (child.getTagName().equals(SdkConstants.CLASS_NESTED_SCROLL_VIEW) && child.children != null && !child.children.isEmpty()) {
- child = child.getChild(0);
- }
- childOfInterest = child;
- break;
- }
- }
- }
-
- if (childOfInterest == null || childOfInterest.children == null || childOfInterest.children.isEmpty()) {
- return childOfInterest;
- }
- return childOfInterest.children.get(childOfInterest.children.size() - 1);
- }
-
- private void updateSelection() {
- if (!mySelectionIsUpdating.compareAndSet(false, true)) {
- return;
- }
- try {
- myTree.clearSelection();
- if (myModel != null) {
- for (NlComponent component : myModel.getSelectionModel().getSelection()) {
- DefaultMutableTreeNode node = myTag2Node.get(component.getTag());
- if (node != null) {
- TreePath path = new TreePath(node.getPath());
- myTree.expandPath(path);
- myTree.addSelectionPath(path);
- }
- }
- }
- } finally {
- mySelectionIsUpdating.set(false);
- }
- }
-
- // ---- Implemented SelectionListener ----
- @Override
- public void selectionChanged(@NonNull SelectionModel model, @NonNull List<NlComponent> selection) {
- UIUtil.invokeLaterIfNeeded(new Runnable() {
- @Override
- public void run() {
- updateSelection();
- }
- });
- }
-
- // ---- Implemented ModelListener ----
- @Override
- public void modelChanged(@NonNull NlModel model) {
- }
-
- @Override
- public void modelRendered(@NonNull NlModel model) {
- UIUtil.invokeLaterIfNeeded(new Runnable() {
- @Override
- public void run() {
- updateHierarchy(false);
- }
- });
- }
-
- // ---- Implemented DesignSurfaceListener ----
-
- @Override
- public void componentSelectionChanged(@NonNull DesignSurface surface, @NonNull List<NlComponent> newSelection) {
- }
-
- @Override
- public void screenChanged(@NonNull DesignSurface surface, @Nullable ScreenView screenView) {
- setModel(screenView != null ? screenView.getModel() : null);
- }
-
- @Override
- public void modelChanged(@NonNull DesignSurface surface, @Nullable NlModel model) {
- if (model != null) {
- modelRendered(model);
- }
- }
-
- private class StructurePaneSelectionListener implements TreeSelectionListener {
- @Override
- public void valueChanged(TreeSelectionEvent treeSelectionEvent) {
- if (!mySelectionIsUpdating.compareAndSet(false, true)) {
- return;
- }
- try {
- List<NlComponent> selected = new ArrayList<NlComponent>();
- TreePath[] paths = myTree.getSelectionPaths();
- if (paths != null) {
- for (TreePath path : myTree.getSelectionPaths()) {
- DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
- selected.add((NlComponent)node.getUserObject());
- }
- }
- myModel.getSelectionModel().setSelection(selected);
- } finally {
- mySelectionIsUpdating.set(false);
- }
- }
- }
}
diff --git a/designer/testSrc/com/android/tools/idea/uibuilder/structure/NlStructurePanelTest.java b/designer/testSrc/com/android/tools/idea/uibuilder/structure/NlComponentTreeTest.java
index b9ef57d6a63..db9a8ca92bf 100644
--- a/designer/testSrc/com/android/tools/idea/uibuilder/structure/NlStructurePanelTest.java
+++ b/designer/testSrc/com/android/tools/idea/uibuilder/structure/NlComponentTreeTest.java
@@ -25,7 +25,6 @@ import com.android.tools.idea.uibuilder.surface.ScreenView;
import org.jetbrains.annotations.NotNull;
import org.mockito.Mock;
-import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.util.Iterator;
@@ -34,13 +33,13 @@ import static com.android.SdkConstants.*;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
-public class NlStructurePanelTest extends LayoutTestCase {
+public class NlComponentTreeTest extends LayoutTestCase {
@Mock
private DesignSurface mySurface;
@Mock
private ScreenView myScreen;
private NlModel myModel;
- private NlStructurePanel myPanel;
+ private NlComponentTree myTree;
@Override
public void setUp() throws Exception {
@@ -50,13 +49,13 @@ public class NlStructurePanelTest extends LayoutTestCase {
when(myScreen.getModel()).thenReturn(myModel);
when(myScreen.getSelectionModel()).thenReturn(myModel.getSelectionModel());
when(mySurface.getCurrentScreenView()).thenReturn(myScreen);
- myPanel = new NlStructurePanel(mySurface);
+ myTree = new NlComponentTree();
+ myTree.setDesignSurface(mySurface);
}
public void testTreeStructure() {
- JTree tree = myPanel.getTree();
NlComponent expectedRoot = myModel.getComponents().get(0);
- DefaultMutableTreeNode hidden = (DefaultMutableTreeNode)tree.getModel().getRoot();
+ DefaultMutableTreeNode hidden = (DefaultMutableTreeNode)myTree.getModel().getRoot();
assertEquals(1, hidden.getChildCount());
DefaultMutableTreeNode root = (DefaultMutableTreeNode)hidden.getFirstChild();
assertEquals("Unexpected root", expectedRoot, root.getUserObject());
@@ -68,16 +67,15 @@ public class NlStructurePanelTest extends LayoutTestCase {
}
public void testSelectionInTreeIsPropagatedToModel() {
- JTree tree = myPanel.getTree();
- assertNull(tree.getSelectionPaths());
+ assertNull(myTree.getSelectionPaths());
assertFalse(myModel.getSelectionModel().getSelection().iterator().hasNext());
- DefaultMutableTreeNode hidden = (DefaultMutableTreeNode)tree.getModel().getRoot();
+ DefaultMutableTreeNode hidden = (DefaultMutableTreeNode)myTree.getModel().getRoot();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)hidden.getFirstChild();
DefaultMutableTreeNode node1 = (DefaultMutableTreeNode)root.getChildAt(1);
DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)root.getChildAt(2);
- tree.addSelectionPath(new TreePath(node1.getPath()));
- tree.addSelectionPath(new TreePath(node2.getPath()));
+ myTree.addSelectionPath(new TreePath(node1.getPath()));
+ myTree.addSelectionPath(new TreePath(node2.getPath()));
Iterator<NlComponent> selected = myModel.getSelectionModel().getSelection().iterator();
assertEquals(node1.getUserObject(), selected.next());
@@ -86,17 +84,18 @@ public class NlStructurePanelTest extends LayoutTestCase {
}
public void testSelectionInModelIsShownInTree() {
- JTree tree = myPanel.getTree();
- assertNull(tree.getSelectionPaths());
+ assertNull(myTree.getSelectionPaths());
assertFalse(myModel.getSelectionModel().getSelection().iterator().hasNext());
NlComponent layout = myModel.getComponents().get(0);
NlComponent text = layout.getChild(0);
NlComponent button = layout.getChild(1);
+ assert text != null;
+ assert button != null;
myModel.getSelectionModel().toggle(text);
myModel.getSelectionModel().toggle(button);
- TreePath[] selection = tree.getSelectionPaths();
+ TreePath[] selection = myTree.getSelectionPaths();
assertEquals(2, selection.length);
assertEquals(text, ((DefaultMutableTreeNode)selection[0].getLastPathComponent()).getUserObject());
assertEquals(button, ((DefaultMutableTreeNode)selection[1].getLastPathComponent()).getUserObject());