diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java index 2221502b153f..9e8ad8fc9e2d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -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> 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); + } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java index 8fbcc73a3caf..356fda1dfcc9 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/AttributeProperty.java @@ -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 { 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 { @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; diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java new file mode 100644 index 000000000000..03f2b7c91d20 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java @@ -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 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 myItems = new ArrayList(); + private final ResourceType myType; + + public ResourceGroup(ResourceType type, ResourceManager manager) { + myType = type; + + Collection 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() { + @Override + public int compare(ResourceItem resource1, ResourceItem resource2) { + return resource1.toString().compareTo(resource2.toString()); + } + }); + } + + public String getName() { + return myType.getName(); + } + + public List 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() { + } + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java index ea286687ea59..8028c3f5e0d4 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/StringsComboEditor.java @@ -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; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java index aea7d02606fc..64d5933f982e 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeNodeDescriptor.java @@ -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; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java index b2aa0f8e20a4..3dda7b490b9f 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java @@ -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}; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java index 224c84f81e13..905b3fc515bc 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyEditor.java @@ -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) { diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java index 61dafdd06cbc..df45e10bf096 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/PropertyTable.java @@ -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); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java index 7e1c5c73b798..68435e5609ee 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/AbstractTextFieldEditor.java @@ -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; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java index 1e181cc43015..d4ac1d7c9bbb 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/propertyTable/editors/BooleanEditor.java @@ -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());