Properties

This commit is contained in:
Alexander Lobas
2012-03-20 21:47:33 +04:00
parent a5738040a5
commit ea42119150
10 changed files with 349 additions and 7 deletions
@@ -16,9 +16,11 @@
package com.intellij.android.designer.model;
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.resources.ResourceType;
import com.android.sdklib.IAndroidTarget;
import com.intellij.android.designer.propertyTable.AttributeProperty;
import com.intellij.android.designer.propertyTable.FlagProperty;
import com.intellij.android.designer.propertyTable.editors.ResourceDialog;
import com.intellij.designer.model.MetaManager;
import com.intellij.designer.model.MetaModel;
import com.intellij.designer.model.RadComponent;
@@ -33,6 +35,7 @@ import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.sdk.AndroidTargetData;
import org.jetbrains.android.uipreview.ProjectClassLoader;
import org.jetbrains.android.uipreview.RenderServiceFactory;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -43,12 +46,14 @@ import java.util.*;
public class PropertyParser {
public static final String KEY = "PROPERTY_PARSER";
private final Module myModule;
private MetaManager myMetaManager;
private AttributeDefinitions myDefinitions;
private ProjectClassLoader myClassLoader;
private Map<String, List<Property>> myCachedProperties;
public PropertyParser(Module module, IAndroidTarget target) throws Exception {
myModule = module;
myMetaManager = ViewsMetaManager.getInstance(module.getProject());
myCachedProperties = myMetaManager.getCache(target.hashString());
if (myCachedProperties == null) {
@@ -166,4 +171,9 @@ public class PropertyParser {
return properties;
}
@NotNull
public ResourceDialog createResourceDialog(ResourceType... types) {
return new ResourceDialog(myModule, types);
}
}
@@ -15,8 +15,11 @@
*/
package com.intellij.android.designer.propertyTable;
import com.android.resources.ResourceType;
import com.intellij.android.designer.model.PropertyParser;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.android.designer.propertyTable.editors.BooleanEditor;
import com.intellij.android.designer.propertyTable.editors.ResourceDialog;
import com.intellij.android.designer.propertyTable.editors.StringsComboEditor;
import com.intellij.android.designer.propertyTable.renderers.BooleanRenderer;
import com.intellij.designer.model.RadComponent;
@@ -26,6 +29,7 @@ import com.intellij.designer.propertyTable.PropertyRenderer;
import com.intellij.designer.propertyTable.editors.AbstractTextFieldEditor;
import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.XmlAttribute;
@@ -141,12 +145,22 @@ public class AttributeProperty extends Property<RadViewComponent> {
private static class TextDialogEditor extends PropertyEditor {
private TextFieldWithBrowseButton myTextField;
private RadComponent myRootComponent;
public TextDialogEditor() {
myTextField = new TextFieldWithBrowseButton(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO: Auto-generated method stub
PropertyParser parser = myRootComponent.getClientProperty(PropertyParser.KEY);
ResourceDialog dialog = parser
.createResourceDialog(ResourceType.BOOL, ResourceType.COLOR, ResourceType.DIMEN, ResourceType.DRAWABLE, ResourceType.INTEGER,
ResourceType.STRING, ResourceType.ID);
dialog.show();
if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
myTextField.setText(dialog.getResourceName());
fireValueCommitted(true, false);
}
}
});
myTextField.getTextField().setBorder(null);
@@ -154,7 +168,8 @@ public class AttributeProperty extends Property<RadViewComponent> {
@NotNull
@Override
public JComponent getComponent(@Nullable RadComponent component, Object value) {
public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) {
myRootComponent = rootComponent;
myTextField.setText(value == null ? "" : value.toString());
myTextField.getTextField().setBorder(null);
return myTextField;
@@ -0,0 +1,308 @@
/*
* 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.propertyTable.editors;
import com.android.resources.ResourceType;
import com.intellij.designer.componentTree.TreeNodeDescriptor;
import com.intellij.ide.util.treeView.AbstractTreeBuilder;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.ide.util.treeView.NodeRenderer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.ui.components.JBTabbedPane;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.List;
/**
* @author Alexander Lobas
*/
public class ResourceDialog extends DialogWrapper implements TreeSelectionListener {
private final JBTabbedPane myContentPanel;
private final ResourcePanel myProjectPanel;
private final ResourcePanel mySystemPanel;
private final Action myNewResourceAction = new AbstractAction("New Resource...") {
@Override
public void actionPerformed(ActionEvent e) {
// TODO: Auto-generated method stub
}
};
private String myResultResourceName;
public ResourceDialog(Module module, ResourceType[] types) {
super(module.getProject());
setTitle("Resource Dialog");
getOKAction().setEnabled(false);
AndroidFacet facet = AndroidFacet.getInstance(module);
myProjectPanel = new ResourcePanel(facet, types, false);
mySystemPanel = new ResourcePanel(facet, types, true);
myContentPanel = new JBTabbedPane();
myContentPanel.setPreferredSize(new Dimension(500, 400));
myContentPanel.addTab("Project", myProjectPanel.myComponent);
myContentPanel.addTab("System", mySystemPanel.myComponent);
myContentPanel.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
myNewResourceAction.setEnabled(myContentPanel.getSelectedComponent() == myProjectPanel.myComponent);
valueChanged(null);
}
});
init();
}
@Override
public JComponent getPreferredFocusedComponent() {
return myProjectPanel.myTree;
}
@Override
protected JComponent createCenterPanel() {
return myContentPanel;
}
@Override
protected Action[] createLeftSideActions() {
return new Action[]{myNewResourceAction};
}
@Override
protected void dispose() {
super.dispose();
Disposer.dispose(myProjectPanel.myTreeBuilder);
Disposer.dispose(mySystemPanel.myTreeBuilder);
}
public String getResourceName() {
return myResultResourceName;
}
@Override
public void valueChanged(TreeSelectionEvent e) {
ResourcePanel panel = myContentPanel.getSelectedComponent() == myProjectPanel.myComponent ? myProjectPanel : mySystemPanel;
Set<ResourceItem> elements = panel.myTreeBuilder.getSelectedElements(ResourceItem.class);
getOKAction().setEnabled(!elements.isEmpty());
if (elements.isEmpty()) {
myResultResourceName = null;
}
else {
String prefix = panel == myProjectPanel ? "@" : "@android:";
myResultResourceName = prefix + elements.iterator().next().getName();
}
}
private class ResourcePanel {
public final Tree myTree;
public final AbstractTreeBuilder myTreeBuilder;
public final JScrollPane myComponent;
public ResourcePanel(AndroidFacet facet, ResourceType[] types, boolean system) {
myTree = new Tree();
myTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
myTree.setScrollsOnExpand(true);
myTree.setRootVisible(false);
myTree.setShowsRootHandles(true);
ToolTipManager.sharedInstance().registerComponent(myTree);
TreeUtil.installActions(myTree);
ResourceManager manager = facet.getResourceManager(system ? AndroidUtils.SYSTEM_RESOURCE_PACKAGE : null);
ResourceGroup[] groups = new ResourceGroup[types.length];
for (int i = 0; i < types.length; i++) {
groups[i] = new ResourceGroup(types[i], manager);
}
myTreeBuilder =
new AbstractTreeBuilder(myTree, (DefaultTreeModel)myTree.getModel(), new TreeContentProvider(groups), null);
myTreeBuilder.initRootNode();
TreeSelectionModel selectionModel = myTree.getSelectionModel();
selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
selectionModel.addTreeSelectionListener(ResourceDialog.this);
myTree.setCellRenderer(new NodeRenderer() {
@Override
protected void doAppend(@NotNull @Nls String fragment,
@NotNull SimpleTextAttributes attributes,
boolean isMainText,
boolean selected) {
SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, attributes, selected, this);
}
@Override
public void doAppend(@NotNull String fragment, @NotNull SimpleTextAttributes attributes, boolean selected) {
SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, attributes, selected, this);
}
@Override
public void doAppend(String fragment, boolean selected) {
SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, SimpleTextAttributes.REGULAR_ATTRIBUTES, selected, this);
}
});
new TreeSpeedSearch(myTree, TreeSpeedSearch.NODE_DESCRIPTOR_TOSTRING, true);
myComponent = ScrollPaneFactory.createScrollPane(myTree);
}
}
private static class ResourceGroup {
private List<ResourceItem> myItems = new ArrayList<ResourceItem>();
private final ResourceType myType;
public ResourceGroup(ResourceType type, ResourceManager manager) {
myType = type;
Collection<String> resourceNames = manager.getValueResourceNames(type.getName());
for (String resourceName : resourceNames) {
myItems.add(new ResourceItem(this, resourceName));
}
for (String file : manager.getFileResourcesNames(type.getName())) {
myItems.add(new ResourceItem(this, file));
}
if (type == ResourceType.ID) {
for (String id : manager.getIds()) {
if (!resourceNames.contains(id)) {
myItems.add(new ResourceItem(this, id));
}
}
}
Collections.sort(myItems, new Comparator<ResourceItem>() {
@Override
public int compare(ResourceItem resource1, ResourceItem resource2) {
return resource1.toString().compareTo(resource2.toString());
}
});
}
public String getName() {
return myType.getName();
}
public List<ResourceItem> getItems() {
return myItems;
}
@Override
public String toString() {
return myType.getDisplayName();
}
}
private static class ResourceItem {
private final ResourceGroup myGroup;
private final String myName;
public ResourceItem(@NotNull ResourceGroup group, @NotNull String name) {
myGroup = group;
myName = name;
}
public ResourceGroup getGroup() {
return myGroup;
}
public String getName() {
return myGroup.getName() + "/" + myName;
}
@Override
public String toString() {
return myName;
}
}
private static class TreeContentProvider extends AbstractTreeStructure {
private final Object myTreeRoot = new Object();
private final ResourceGroup[] myGroups;
public TreeContentProvider(ResourceGroup[] groups) {
myGroups = groups;
}
@Override
public Object getRootElement() {
return myTreeRoot;
}
@Override
public Object[] getChildElements(Object element) {
if (element == myTreeRoot) {
return myGroups;
}
if (element instanceof ResourceGroup) {
ResourceGroup group = (ResourceGroup)element;
return group.getItems().toArray();
}
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Override
public Object getParentElement(Object element) {
if (element instanceof ResourceItem) {
ResourceItem resource = (ResourceItem)element;
return resource.getGroup();
}
return null;
}
@NotNull
@Override
public NodeDescriptor createDescriptor(Object element, NodeDescriptor parentDescriptor) {
return new TreeNodeDescriptor(parentDescriptor, element, element == null ? null : element.toString());
}
@Override
public boolean hasSomethingToCommit() {
return false;
}
@Override
public void commit() {
}
}
}
@@ -32,7 +32,7 @@ public class StringsComboEditor extends ComboEditor {
@NotNull
@Override
public JComponent getComponent(@Nullable RadComponent component, Object value) {
public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) {
myCombo.setSelectedItem(value);
return myCombo;
}
@@ -30,6 +30,11 @@ public final class TreeNodeDescriptor extends NodeDescriptor {
myElement = element;
}
public TreeNodeDescriptor(@Nullable NodeDescriptor parentDescriptor, Object element, String name) {
this(parentDescriptor, element);
myName = name;
}
@Override
public boolean update() {
return false;
@@ -359,6 +359,10 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
return myDesignerCard.isVisible() ? myGlassLayer : myErrorLabel;
}
public RadComponent getRootComponent() {
return myRootComponent;
}
public Object[] getTreeRoots() {
return myRootComponent == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[]{myRootComponent};
}
@@ -29,7 +29,7 @@ public abstract class PropertyEditor {
private final EventListenerList myListenerList = new EventListenerList();
@NotNull
public abstract JComponent getComponent(@Nullable RadComponent component, Object value);
public abstract JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value);
@Nullable
public JComponent getPreferredFocusedComponent(@NotNull JComponent component) {
@@ -821,7 +821,7 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
try {
JComponent component = myEditor.getComponent(getCurrentComponent(), getValue((Property)value));
JComponent component = myEditor.getComponent(myDesigner.getRootComponent(), getCurrentComponent(), getValue((Property)value));
if (component instanceof JComboBox) {
component.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
@@ -41,7 +41,7 @@ public abstract class AbstractTextFieldEditor extends PropertyEditor {
@NotNull
@Override
public JComponent getComponent(@Nullable RadComponent component, Object value) {
public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) {
setEditorValue(component, value);
myTextField.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));
return myTextField;
@@ -57,7 +57,7 @@ public class BooleanEditor extends PropertyEditor {
}
@NotNull
public JComponent getComponent(@Nullable RadComponent component, Object value) {
public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) {
try {
myInsideChange = true;
myCheckBox.setBackground(UIUtil.getTableBackground());