Work on ComponentTree

This commit is contained in:
Alexander Lobas
2012-02-10 23:01:53 +04:00
parent c9568b7eb0
commit b21b9d1d3f
13 changed files with 462 additions and 5 deletions
@@ -15,8 +15,12 @@
*/
package com.intellij.android.designer;
import com.intellij.android.designer.designSurface.AndroidDesignerEditorPanel;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.openapi.fileEditor.FileEditorState;
import com.intellij.openapi.fileEditor.FileEditorStateLevel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.designer.DesignerEditor;
@@ -30,6 +34,11 @@ public final class AndroidDesignerEditor extends DesignerEditor {
super(project, file);
}
@Override
protected DesignerEditorPanel createDesignerPanel(Module module, VirtualFile file) {
return new AndroidDesignerEditorPanel(module, file);
}
@NotNull
@Override
public String getName() {
@@ -0,0 +1,32 @@
/*
* 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.android.designer.componentTree;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.model.RadComponent;
import com.intellij.ui.ColoredTreeCellRenderer;
/**
* @author Alexander Lobas
*/
public final class AndroidTreeDecorator extends TreeComponentDecorator {
@Override
public void decorate(RadComponent component, ColoredTreeCellRenderer renderer) {
RadViewComponent view = (RadViewComponent)component;
renderer.append(view.getTitle());
}
}
@@ -0,0 +1,79 @@
/*
* 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.android.designer.designSurface;
import com.intellij.android.designer.componentTree.AndroidTreeDecorator;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.designer.model.RadComponent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
/**
* @author Alexander Lobas
*/
public final class AndroidDesignerEditorPanel extends DesignerEditorPanel {
private final TreeComponentDecorator myTreeDecorator = new AndroidTreeDecorator();
public AndroidDesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) {
super(module, file);
// (temp code) TODO: use platform DOM
try {
InputStream stream = file.getInputStream();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(stream, new DefaultHandler() {
RadViewComponent myComponent;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
myComponent = new RadViewComponent(myComponent, qName);
if (myRootComponent == null) {
myRootComponent = myComponent;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (myComponent != null) {
myComponent = (RadViewComponent)myComponent.getParent();
}
}
});
stream.close();
}
catch (Throwable e) {
e.printStackTrace(); // TODO
}
}
@Override
public TreeComponentDecorator getTreeDecorator() {
return myTreeDecorator;
}
}
@@ -0,0 +1,48 @@
/*
* 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.android.designer.model;
import com.intellij.designer.model.RadComponent;
import java.util.ArrayList;
import java.util.List;
/**
* TODO: now dummy implementation for tests
*
* @author Alexander Lobas
*/
public class RadViewComponent extends RadComponent {
private final String myTitle;
private final List<RadComponent> myChildren = new ArrayList<RadComponent>();
public RadViewComponent(RadViewComponent parent, String title) {
myTitle = title;
setParent(parent);
if (parent != null) {
parent.getChildren().add(this);
}
}
@Override
public List<RadComponent> getChildren() {
return myChildren;
}
public String getTitle() {
return myTitle;
}
}
@@ -45,9 +45,11 @@ public abstract class DesignerEditor extends UserDataHolderBase implements FileE
if (module == null) {
throw new IllegalArgumentException("No module for file " + file + " in project " + project);
}
myDesignerPanel = new DesignerEditorPanel(module, file);
myDesignerPanel = createDesignerPanel(module, file);
}
protected abstract DesignerEditorPanel createDesignerPanel(Module module, VirtualFile file);
public final DesignerEditorPanel getDesignerPanel() {
return myDesignerPanel;
}
@@ -16,8 +16,10 @@
package com.intellij.designer;
import com.intellij.designer.componentTree.ComponentTree;
import com.intellij.designer.componentTree.ComponentTreeBuilder;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.designer.propertyTable.PropertyTablePanel;
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
@@ -26,6 +28,7 @@ import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
@@ -53,6 +56,7 @@ public final class DesignerToolWindowManager implements ProjectComponent {
private final FileEditorManager myFileEditorManager;
private ToolWindow myToolWindow;
private ComponentTree myComponentTree;
private AbstractTreeBuilder myTreeBuilder;
private PropertyTablePanel myPropertyTablePanel;
private boolean myToolWindowReady;
private boolean myToolWindowDisposed;
@@ -91,12 +95,20 @@ public final class DesignerToolWindowManager implements ProjectComponent {
public void projectClosed() {
if (!myToolWindowDisposed) {
myToolWindowDisposed = true;
clearTreeBuilder();
myComponentTree = null;
myPropertyTablePanel = null;
myToolWindow = null;
}
}
private void clearTreeBuilder() {
if (myTreeBuilder != null) {
Disposer.dispose(myTreeBuilder);
myTreeBuilder = null;
}
}
public static DesignerToolWindowManager getInstance(Project project) {
return project.getComponent(DesignerToolWindowManager.class);
}
@@ -128,10 +140,15 @@ public final class DesignerToolWindowManager implements ProjectComponent {
}
initToolWindow();
}
clearTreeBuilder();
myComponentTree.newModel();
if (designer == null) {
myComponentTree.setDecorator(null);
myToolWindow.setAvailable(false, null);
}
else {
myComponentTree.setDecorator(designer.getTreeDecorator());
myTreeBuilder = new ComponentTreeBuilder(myComponentTree, designer);
myToolWindow.setAvailable(true, null);
myToolWindow.show(null);
}
@@ -15,10 +15,15 @@
*/
package com.intellij.designer.componentTree;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.designer.model.RadComponent;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NonNls;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
@@ -26,12 +31,62 @@ import javax.swing.tree.DefaultTreeModel;
* @author Alexander Lobas
*/
public final class ComponentTree extends Tree implements DataProvider {
private TreeComponentDecorator myDecorator;
public ComponentTree() {
super(new DefaultTreeModel(new DefaultMutableTreeNode()));
newModel();
installCellRenderer();
setRootVisible(false);
setShowsRootHandles(true);
// Enable tooltips
ToolTipManager.sharedInstance().registerComponent(this);
// Install convenient keyboard navigation
TreeUtil.installActions(this);
// TODO: Popup menu
// TODO: F2 should start inplace editing
// TODO: DND
}
public void newModel() {
setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
}
public void setDecorator(TreeComponentDecorator decorator) {
myDecorator = decorator;
}
@Override
public Object getData(@NonNls String dataId) {
return null; //To change body of implemented methods use File | Settings | File Templates.
return null; //TODO
}
private void installCellRenderer() {
setCellRenderer(new ColoredTreeCellRenderer() {
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
if (myDecorator != null && node.getUserObject() instanceof TreeNodeDescriptor) {
TreeNodeDescriptor descriptor = (TreeNodeDescriptor)node.getUserObject();
if (descriptor.getElement() instanceof RadComponent) {
RadComponent component = (RadComponent)descriptor.getElement();
// TODO: support more parameters and attributes
myDecorator.decorate(component, this);
}
}
}
});
}
}
@@ -0,0 +1,36 @@
/*
* 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.designer.componentTree;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.ide.util.treeView.NodeDescriptor;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import java.util.Comparator;
/**
* @author Alexander Lobas
*/
public final class ComponentTreeBuilder extends AbstractTreeBuilder {
public ComponentTreeBuilder(ComponentTree tree, DesignerEditorPanel designer) {
super(tree, (DefaultTreeModel)tree.getModel(), new TreeContentProvider(designer), null); // TODO: comparator?
initRootNode();
}
}
@@ -0,0 +1,26 @@
/*
* 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.designer.componentTree;
import com.intellij.designer.model.RadComponent;
import com.intellij.ui.ColoredTreeCellRenderer;
/**
* @author Alexander Lobas
*/
public abstract class TreeComponentDecorator {
public abstract void decorate(RadComponent component, ColoredTreeCellRenderer renderer); // TODO: more parameters and attributes
}
@@ -0,0 +1,83 @@
/*
* 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.designer.componentTree;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.designer.model.RadComponent;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
/**
* @author Alexander Lobas
*/
public final class TreeContentProvider extends AbstractTreeStructure {
private final DesignerEditorPanel myDesigner;
private final Object myTreeRoot = new Object();
public TreeContentProvider(DesignerEditorPanel designer) {
myDesigner = designer;
}
@Override
public Object getRootElement() {
return myTreeRoot;
}
@Override
public Object[] getChildElements(Object element) {
if (element == myTreeRoot) {
return myDesigner.getTreeRoots();
}
else if (element instanceof RadComponent) {
RadComponent component = (RadComponent)element;
return component.getTreeChildren();
}
else {
throw new IllegalArgumentException("Unknown element: " + element);
}
}
@Override
public Object getParentElement(Object element) {
if (element instanceof RadComponent) {
RadComponent component = (RadComponent)element;
return component.getParent();
}
return null;
}
@NotNull
@Override
public NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) {
if (element == myTreeRoot || element instanceof RadComponent) {
return new TreeNodeDescriptor(parentDescriptor, element);
}
else {
throw new IllegalArgumentException("Unknown element: " + element);
}
}
@Override
public boolean hasSomethingToCommit() {
return false;
}
@Override
public void commit() {
}
}
@@ -0,0 +1,42 @@
/*
* 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.designer.componentTree;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.Nullable;
/**
* @author Alexander Lobas
*/
public final class TreeNodeDescriptor extends NodeDescriptor {
private final Object myElement;
public TreeNodeDescriptor(@Nullable NodeDescriptor parentDescriptor, Object element) {
super(null, parentDescriptor);
myElement = element;
}
@Override
public boolean update() {
return false;
}
@Override
public Object getElement() {
return myElement;
}
}
@@ -15,9 +15,12 @@
*/
package com.intellij.designer.designSurface;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.model.RadComponent;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -27,7 +30,9 @@ import java.awt.*;
/**
* @author Alexander Lobas
*/
public final class DesignerEditorPanel extends JPanel implements DataProvider {
public abstract class DesignerEditorPanel extends JPanel implements DataProvider {
protected RadComponent myRootComponent;
public DesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) {
setLayout(new BorderLayout());
add(new JLabel("Design Surface", JLabel.CENTER), BorderLayout.CENTER);
@@ -45,4 +50,10 @@ public final class DesignerEditorPanel extends JPanel implements DataProvider {
public JComponent getPreferredFocusedComponent() {
return null; // TODO: Auto-generated method stub
}
public Object[] getTreeRoots() {
return myRootComponent == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[]{myRootComponent};
}
public abstract TreeComponentDecorator getTreeDecorator();
}
@@ -16,14 +16,19 @@
package com.intellij.designer.model;
import com.intellij.designer.propertyTable.Property;
import com.intellij.util.containers.hash.HashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @author Alexander Lobas
*/
public abstract class RadComponent {
private RadComponent myParent;
private final Map<Object, Object> myClientProperties = new HashMap<Object, Object>();
public RadComponent getRoot() {
return myParent == null ? this : myParent.getRoot();
@@ -38,10 +43,22 @@ public abstract class RadComponent {
}
public List<RadComponent> getChildren() {
return null;
return Collections.emptyList();
}
public Object[] getTreeChildren() {
return getChildren().toArray();
}
public List<Property> getProperties() {
return null;
}
public final Object getClientProperty(@NotNull Object key) {
return myClientProperties.get(key);
}
public final void putClientProperty(@NotNull Object key, Object value) {
myClientProperties.put(key, value);
}
}