/**
   * Returns the list of source files for a given resource. Optionally, if a {@link
   * FolderConfiguration} is given, then only the best match for this config is returned.
   *
   * @param type the type of the resource.
   * @param name the name of the resource.
   * @param referenceConfig an optional config for which only the best match will be returned.
   * @return a list of files generating this resource or null if it was not found.
   */
  @Nullable
  public List<ResourceFile> getSourceFiles(
      @NonNull ResourceType type,
      @NonNull String name,
      @Nullable FolderConfiguration referenceConfig) {
    ensureInitialized();

    Collection<ResourceItem> items = getResourceItemsOfType(type);

    for (ResourceItem item : items) {
      if (name.equals(item.getName())) {
        if (referenceConfig != null) {
          Configurable match = referenceConfig.findMatchingConfigurable(item.getSourceFileList());

          if (match instanceof ResourceFile) {
            return Collections.singletonList((ResourceFile) match);
          }

          return null;
        }
        return item.getSourceFileList();
      }
    }

    return null;
  }
  @Override
  public void valueChanged(@Nullable TreeSelectionEvent e) {
    Component selectedComponent = myContentPanel.getSelectedComponent();

    if (selectedComponent == myColorPickerPanel) {
      Color color = myColorPicker.getColor();
      myNewResourceAction.setEnabled(false);
      myResultResourceName = ResourceHelper.colorToString(color);
      updateResourceNameStatus();
    } else {
      boolean isProjectPanel = selectedComponent == myProjectPanel.myComponent;
      ResourcePanel panel = isProjectPanel ? myProjectPanel : mySystemPanel;
      ResourceItem element = getSelectedElement(panel.myTreeBuilder, ResourceItem.class);
      setOKActionEnabled(element != null);
      myNewResourceAction.setEnabled(
          isProjectPanel && !panel.myTreeBuilder.getSelectedElements().isEmpty());

      if (element == null) {
        myResultResourceName = null;
      } else {
        String prefix = panel == myProjectPanel ? "@" : ANDROID;
        myResultResourceName = prefix + element.getName();
      }

      panel.showPreview(element);
    }
    notifyResourcePickerListeners(myResultResourceName);
  }
 protected void removeFile(@NonNull ResourceType type, @NonNull ResourceFile file) {
   Map<String, ResourceItem> map = mResourceMap.get(type);
   if (map != null) {
     Collection<ResourceItem> values = map.values();
     List<ResourceItem> toDelete = null;
     for (ResourceItem item : values) {
       item.removeFile(file);
       if (item.hasNoSourceFile()) {
         if (toDelete == null) {
           toDelete = new ArrayList<ResourceItem>(values.size());
         }
         toDelete.add(item);
       }
     }
     if (toDelete != null) {
       for (ResourceItem item : toDelete) {
         map.remove(item.getName());
       }
     }
   }
 }
  /**
   * Returns a map of (resource name, resource value) for the given {@link ResourceType}.
   *
   * <p>The values returned are taken from the resource files best matching a given {@link
   * FolderConfiguration}.
   *
   * @param type the type of the resources.
   * @param referenceConfig the configuration to best match.
   */
  @NonNull
  private Map<String, ResourceValue> getConfiguredResource(
      @NonNull ResourceType type, @NonNull FolderConfiguration referenceConfig) {

    // get the resource item for the given type
    Map<String, ResourceItem> items = mResourceMap.get(type);
    if (items == null) {
      return new HashMap<String, ResourceValue>();
    }

    // create the map
    HashMap<String, ResourceValue> map = new HashMap<String, ResourceValue>(items.size());

    for (ResourceItem item : items.values()) {
      ResourceValue value = item.getResourceValue(type, referenceConfig, isFrameworkRepository());
      if (value != null) {
        map.put(item.getName(), value);
      }
    }

    return map;
  }
  /**
   * Returns a {@link ResourceItem} matching the given {@link ResourceType} and name. If none exist,
   * it creates one.
   *
   * @param type the resource type
   * @param name the name of the resource.
   * @return A resource item matching the type and name.
   */
  @NonNull
  public ResourceItem getResourceItem(@NonNull ResourceType type, @NonNull String name) {
    ensureInitialized();

    // looking for an existing ResourceItem with this type and name
    ResourceItem item = findDeclaredResourceItem(type, name);

    // create one if there isn't one already, or if the existing one is inlined, since
    // clearly we need a non inlined one (the inline one is removed too)
    if (item == null || item.isDeclaredInline()) {
      ResourceItem oldItem = item != null && item.isDeclaredInline() ? item : null;

      item = createResourceItem(name);

      Map<String, ResourceItem> map = mResourceMap.get(type);

      if (map == null) {
        if (isFrameworkRepository()) {
          // Pick initial size for the maps. Also change the load factor to 1.0
          // to avoid rehashing the whole table when we (as expected) get near
          // the known rough size of each resource type map.
          int size;
          switch (type) {
              // Based on counts in API 16. Going back to API 10, the counts
              // are roughly 25-50% smaller (e.g. compared to the top 5 types below
              // the fractions are 1107 vs 1734, 831 vs 1508, 895 vs 1255,
              // 733 vs 1064 and 171 vs 783.
            case PUBLIC:
              size = 1734;
              break;
            case DRAWABLE:
              size = 1508;
              break;
            case STRING:
              size = 1255;
              break;
            case ATTR:
              size = 1064;
              break;
            case STYLE:
              size = 783;
              break;
            case ID:
              size = 347;
              break;
            case DECLARE_STYLEABLE:
              size = 210;
              break;
            case LAYOUT:
              size = 187;
              break;
            case COLOR:
              size = 120;
              break;
            case ANIM:
              size = 95;
              break;
            case DIMEN:
              size = 81;
              break;
            case BOOL:
              size = 54;
              break;
            case INTEGER:
              size = 52;
              break;
            case ARRAY:
              size = 51;
              break;
            case PLURALS:
              size = 20;
              break;
            case XML:
              size = 14;
              break;
            case INTERPOLATOR:
              size = 13;
              break;
            case ANIMATOR:
              size = 8;
              break;
            case RAW:
              size = 4;
              break;
            case MENU:
              size = 2;
              break;
            case MIPMAP:
              size = 2;
              break;
            case FRACTION:
              size = 1;
              break;
            default:
              size = 2;
          }
          map = new HashMap<String, ResourceItem>(size, 1.0f);
        } else {
          map = new HashMap<String, ResourceItem>();
        }
        mResourceMap.put(type, map);
      }

      map.put(item.getName(), item);

      if (oldItem != null) {
        map.remove(oldItem.getName());
      }
    }

    return item;
  }