Merge "Add color filtering." into studio-1.3-dev
automerge: 277133b

* commit '277133b00d475c5e9565e70d11688e41b4b87036':
  Add color filtering.
diff --git a/android/src/com/android/tools/idea/editors/theme/ColorPalette.java b/android/src/com/android/tools/idea/editors/theme/ColorPalette.java
index e486485..b7373c2 100644
--- a/android/src/com/android/tools/idea/editors/theme/ColorPalette.java
+++ b/android/src/com/android/tools/idea/editors/theme/ColorPalette.java
@@ -55,11 +55,18 @@
     /**
      * Returns the element located at the index {@code i}.
      */
+    @NotNull
     Color getColorAt(int i);
 
     /**
+     * Returns the index a given color or -1 if it doesn't exist.
+     */
+    int indexOf(@NotNull Color c);
+
+    /**
      * Returns the tooltip for the element located at the index {@code i}.
      */
+    @NotNull
     String getToolTipAt(int i);
   }
 
@@ -78,12 +85,19 @@
       return myColorList.size();
     }
 
+    @NotNull
     @Override
     public Color getColorAt(int i) {
       return myColorList.get(i);
     }
 
     @Override
+    public int indexOf(@NotNull Color c) {
+      return myColorList.indexOf(c);
+    }
+
+    @NotNull
+    @Override
     public String getToolTipAt(int i) {
       return myColorList.get(i).toString();
     }
@@ -110,10 +124,11 @@
         if (selected != -1) {
           mySelectedItem = selected;
           itemStateChanged(mySelectedItem, ItemEvent.SELECTED);
-        } else {
+          repaint();
+        }
+        else {
           clearSelection();
         }
-        repaint();
       }
     });
   }
@@ -123,12 +138,17 @@
     this(new StaticColorPaletteModel(Collections.<Color>emptyList()));
   }
 
-  public void setModel(ColorPaletteModel colorListModel) {
+  public void setModel(@NotNull ColorPaletteModel colorListModel) {
     myColorListModel = colorListModel;
 
     revalidate();
   }
 
+  @NotNull
+  public ColorPaletteModel getModel() {
+    return myColorListModel;
+  }
+
   /**
    * Sets the size of each color box in pixels.
    */
@@ -215,7 +235,9 @@
       g.fillRect(x, myColorBoxPadding, myColorBoxSize, myColorBoxSize);
 
       if (mySelectedItem == i && mySelectedBorder != null) {
+        g.setXORMode(Color.WHITE);
         mySelectedBorder.paintBorder(this, g, x, myColorBoxPadding, myColorBoxSize, myColorBoxSize);
+        g.setPaintMode();
       }
 
       if (x > width) {
@@ -274,6 +296,8 @@
 
   public void clearSelection() {
     mySelectedItem = -1;
+
+    repaint();
   }
 
   private void itemStateChanged(int position, int stateChange) {
diff --git a/android/src/com/android/tools/idea/editors/theme/ThemeEditorComponent.java b/android/src/com/android/tools/idea/editors/theme/ThemeEditorComponent.java
index d5ae69e..b4f0aa7 100644
--- a/android/src/com/android/tools/idea/editors/theme/ThemeEditorComponent.java
+++ b/android/src/com/android/tools/idea/editors/theme/ThemeEditorComponent.java
@@ -46,7 +46,6 @@
 import com.intellij.ui.components.JBScrollPane;
 import com.intellij.util.Processor;
 import com.intellij.util.ui.UIUtil;
-import org.jetbrains.android.dom.attrs.AttributeDefinitions;
 import org.jetbrains.android.dom.drawable.DrawableDomElement;
 import org.jetbrains.android.dom.resources.Flag;
 import org.jetbrains.android.dom.resources.ResourceElement;
@@ -68,6 +67,7 @@
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -187,11 +187,17 @@
                                                                                 new FlagRendererEditor()));
     myAttributesTable.setDefaultRenderer(ThemeEditorStyle.class,
                                          new DelegatingCellRenderer(myModule, myConfiguration, false, myStyleEditor));
-    myAttributesTable.setDefaultRenderer(DrawableDomElement.class,
-                                         new DelegatingCellRenderer(myModule, myConfiguration, false, new DrawableRenderer(myAttributesTable, renderTask)));
+    myAttributesTable.setDefaultRenderer(DrawableDomElement.class, new DelegatingCellRenderer(myModule, myConfiguration, false,
+                                                                                              new DrawableRenderer(myAttributesTable,
+                                                                                                                   renderTask)));
     myAttributesTable.setDefaultRenderer(TableLabel.class, new DefaultTableCellRenderer() {
       @Override
-      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+      public Component getTableCellRendererComponent(JTable table,
+                                                     Object value,
+                                                     boolean isSelected,
+                                                     boolean hasFocus,
+                                                     int row,
+                                                     int column) {
         super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
         this.setFont(HEADER_FONT);
         return this;
@@ -220,14 +226,16 @@
       }
     });
 
-    myPanel.getAdvancedFilterCheckBox().addItemListener(new ItemListener() {
+    myPanel.getAdvancedFilterCheckBox().addActionListener(new ActionListener() {
       @Override
-      public void itemStateChanged(ItemEvent e) {
+      public void actionPerformed(ActionEvent e) {
         if (myAttributesTable.isEditing()) {
           myAttributesTable.getCellEditor().cancelCellEditing();
         }
+
         myAttributesTable.clearSelection();
-        myAttributesFilter.setAdvancedMode(myPanel.isAdvancedMode());
+        myPanel.getPalette().clearSelection();
+        myAttributesFilter.setFilterEnabled(!myPanel.isAdvancedMode());
 
         myAttributesFilter.setAttributesFilter(myPreviewPanel.getUsedAttrs());
 
@@ -539,8 +547,8 @@
       myStyleEditor.setAreDetailsActive(true);
     }
 
-    // Setting advanced to true here is a required workaround until we fix the hack to set the cell height below.
-    myAttributesFilter.setAdvancedMode(true);
+    // Disabling the filter here is a required workaround until we fix the hack to set the cell height below.
+    myAttributesFilter.setFilterEnabled(false);
     myPanel.getBackButton().setVisible(myCurrentSubStyle != null);
     myPanel.getPalette().setVisible(myCurrentSubStyle == null);
     myConfiguration.setTheme(selectedTheme.getName());
@@ -586,7 +594,8 @@
                 }
               }
             }
-          } else {
+          }
+          else {
             reload(myPreviousSelectedTheme);
           }
         }
@@ -611,7 +620,7 @@
     TableRowSorter<AttributesTableModel> sorter = new TableRowSorter<AttributesTableModel>(model);
     sorter.setRowFilter(myAttributesFilter);
     myAttributesTable.setRowSorter(sorter);
-    myPanel.setAdvancedMode(myAttributesFilter.myAdvancedMode);
+    myPanel.setAdvancedMode(!myAttributesFilter.myIsFilterEnabled);
 
     ActionListener listener = new ActionListener() {
       @Override
@@ -624,6 +633,29 @@
     model.parentAttribute.setGotoDefinitionCallback(listener);
 
     myPanel.getPalette().setModel(new AttributesModelColorPaletteModel(myConfiguration, model));
+    myPanel.getPalette().addItemListener(new ItemListener() {
+      @Override
+      public void itemStateChanged(ItemEvent e) {
+        if (e.getStateChange() == ItemEvent.SELECTED) {
+          AttributesModelColorPaletteModel model = (AttributesModelColorPaletteModel)myPanel.getPalette().getModel();
+          List<EditedStyleItem> references = model.getReferences((Color)e.getItem());
+          if (references.isEmpty()) {
+            return;
+          }
+
+          HashSet<String> attributeNames = new HashSet<String>(references.size());
+          for(EditedStyleItem item : references) {
+            attributeNames.add(item.getQualifiedName());
+          }
+          myAttributesFilter.setAttributesFilter(attributeNames);
+          myAttributesFilter.setFilterEnabled(true);
+        } else {
+          myAttributesFilter.setFilterEnabled(false);
+        }
+        ((TableRowSorter)myAttributesTable.getRowSorter()).sort();
+        myPanel.getAdvancedFilterCheckBox().getModel().setSelected(!myAttributesFilter.myIsFilterEnabled);
+      }
+    });
 
     //We calling this to trigger tableChanged, which will calculate row heights and rePaint myPreviewPanel
     model.fireTableStructureChanged();
@@ -637,19 +669,15 @@
 
   class StyleAttributesFilter extends RowFilter<AttributesTableModel, Integer> {
     // TODO: This is just a random list of attributes. Replace with a possibly dynamic list of simple attributes.
-    private final Set<String> SIMPLE_ATTRIBUTES = ImmutableSet
+    public final Set<String> ATTRIBUTES_DEFAULT_FILTER = ImmutableSet
       .of("android:background", "android:colorAccent", "android:colorBackground", "android:colorForegroundInverse", "android:colorPrimary",
           "android:editTextColor", "spinnerStyle", "android:textColorHighlight", "android:textColorLinkInverse", "android:textColorPrimary",
           "windowTitleStyle", "android:windowFullscreen");
-    private boolean myAdvancedMode = true;
-    private boolean myLocallyDefinedMode = false;
-    private Set<String> filterAttributes = SIMPLE_ATTRIBUTES;
+    private boolean myIsFilterEnabled = true;
+    private Set<String> filterAttributes = ATTRIBUTES_DEFAULT_FILTER;
 
-    public void setOnlyLocallyDefinedMode(boolean local) {
-      this.myLocallyDefinedMode = local;
-    }
-    public void setAdvancedMode(boolean advanced) {
-      this.myAdvancedMode = advanced;
+    public void setFilterEnabled(boolean enabled) {
+      this.myIsFilterEnabled = enabled;
     }
 
     /**
@@ -661,12 +689,16 @@
 
     @Override
     public boolean include(Entry<? extends AttributesTableModel, ? extends Integer> entry) {
+      if (!myIsFilterEnabled) {
+        return true;
+      }
+
       // We use the column 1 because it's the one that contains the ItemResourceValueWrapper.
       Object value = entry.getModel().getValueAt(entry.getIdentifier().intValue(), 1);
       String attributeName;
 
       if (value instanceof TableLabel) {
-        return myAdvancedMode;
+        return false;
       }
       if (value instanceof EditedStyleItem) {
         attributeName = ((EditedStyleItem)value).getQualifiedName();
@@ -680,14 +712,6 @@
         LOG.error("No theme selected.");
         return false;
       }
-      if (myLocallyDefinedMode && !selectedTheme.isAttributeDefined(attributeName)) {
-        return false;
-      }
-
-      if (myAdvancedMode) {
-        // All Attributes shown.
-        return true;
-      }
 
       return filterAttributes.contains(attributeName);
     }
diff --git a/android/src/com/android/tools/idea/editors/theme/attributes/AttributesModelColorPaletteModel.java b/android/src/com/android/tools/idea/editors/theme/attributes/AttributesModelColorPaletteModel.java
index 45bd2bf..5e6c7d7 100644
--- a/android/src/com/android/tools/idea/editors/theme/attributes/AttributesModelColorPaletteModel.java
+++ b/android/src/com/android/tools/idea/editors/theme/attributes/AttributesModelColorPaletteModel.java
@@ -57,12 +57,19 @@
     return myColorList.size();
   }
 
+  @NotNull
   @Override
   public Color getColorAt(int i) {
     return myColorList.get(i);
   }
 
   @Override
+  public int indexOf(@NotNull Color c) {
+    return myColorList.indexOf(c);
+  }
+
+  @NotNull
+  @Override
   public String getToolTipAt(int i) {
     StringBuilder tooltip = new StringBuilder("This color is used in:\n\n");
     for(EditedStyleItem item : myColorReferences.get(myColorList.get(i))) {
@@ -98,4 +105,8 @@
   public void tableChanged(TableModelEvent e) {
     loadColors();
   }
+
+  public List<EditedStyleItem> getReferences(Color color) {
+    return ImmutableList.copyOf(myColorReferences.get(color));
+  }
 }