private void createNewResourceValue(ResourceType resourceType) {
    CreateXmlResourceDialog dialog =
        new CreateXmlResourceDialog(myModule, resourceType, null, null, true);
    dialog.setTitle(
        "New " + StringUtil.capitalize(resourceType.getDisplayName()) + " Value Resource");
    if (!dialog.showAndGet()) {
      return;
    }

    Module moduleToPlaceResource = dialog.getModule();
    if (moduleToPlaceResource == null) {
      return;
    }

    String fileName = dialog.getFileName();
    List<String> dirNames = dialog.getDirNames();
    String resValue = dialog.getValue();
    String resName = dialog.getResourceName();
    if (!AndroidResourceUtil.createValueResource(
        moduleToPlaceResource, resName, resourceType, fileName, dirNames, resValue)) {
      return;
    }

    PsiDocumentManager.getInstance(myModule.getProject()).commitAllDocuments();

    myResultResourceName = "@" + resourceType.getName() + "/" + resName;
    close(OK_EXIT_CODE);
  }
Ejemplo n.º 2
0
  /**
   * Returns true if this resource repository contains a resource of the given name.
   *
   * @param url the resource URL
   * @return true if the resource is known
   */
  public boolean hasResourceItem(@NonNull String url) {
    // Handle theme references
    if (url.startsWith(PREFIX_THEME_REF)) {
      String remainder = url.substring(PREFIX_THEME_REF.length());
      if (url.startsWith(ATTR_REF_PREFIX)) {
        url = PREFIX_RESOURCE_REF + url.substring(PREFIX_THEME_REF.length());
        return hasResourceItem(url);
      }
      int colon = url.indexOf(':');
      if (colon != -1) {
        // Convert from ?android:progressBarStyleBig to ?android:attr/progressBarStyleBig
        if (remainder.indexOf('/', colon) == -1) {
          remainder =
              remainder.substring(0, colon) + RESOURCE_CLZ_ATTR + '/' + remainder.substring(colon);
        }
        url = PREFIX_RESOURCE_REF + remainder;
        return hasResourceItem(url);
      } else {
        int slash = url.indexOf('/');
        if (slash == -1) {
          url = PREFIX_RESOURCE_REF + RESOURCE_CLZ_ATTR + '/' + remainder;
          return hasResourceItem(url);
        }
      }
    }

    if (!url.startsWith(PREFIX_RESOURCE_REF)) {
      return false;
    }

    assert url.startsWith("@") || url.startsWith("?") : url;

    ensureInitialized();

    int typeEnd = url.indexOf('/', 1);
    if (typeEnd != -1) {
      int nameBegin = typeEnd + 1;

      // Skip @ and @+
      int typeBegin = url.startsWith("@+") ? 2 : 1; // $NON-NLS-1$

      int colon = url.lastIndexOf(':', typeEnd);
      if (colon != -1) {
        typeBegin = colon + 1;
      }
      String typeName = url.substring(typeBegin, typeEnd);
      ResourceType type = ResourceType.getEnum(typeName);
      if (type != null) {
        String name = url.substring(nameBegin);
        return hasResourceItem(type, name);
      }
    }

    return false;
  }
  @Nullable
  public static ValidationInfo checkIfResourceAlreadyExists(
      @NotNull Module selectedModule,
      @NotNull String resourceName,
      @NotNull ResourceType resourceType,
      @NotNull List<String> dirNames,
      @NotNull String fileName) {
    if (resourceName.length() == 0 || dirNames.size() == 0 || fileName.length() == 0) {
      return null;
    }

    final AndroidFacet facet = AndroidFacet.getInstance(selectedModule);
    final VirtualFile resourceDir = facet != null ? AndroidRootUtil.getResourceDir(facet) : null;
    if (resourceDir == null) {
      return null;
    }

    for (String directoryName : dirNames) {
      final VirtualFile resourceSubdir = resourceDir.findChild(directoryName);
      if (resourceSubdir == null) {
        continue;
      }

      final VirtualFile resFile = resourceSubdir.findChild(fileName);
      if (resFile == null) {
        continue;
      }

      if (resFile.getFileType() != StdFileTypes.XML) {
        return new ValidationInfo(
            "File " + FileUtil.toSystemDependentName(resFile.getPath()) + " is not XML file");
      }

      final Resources resources =
          AndroidUtils.loadDomElement(selectedModule, resFile, Resources.class);
      if (resources == null) {
        return new ValidationInfo(
            AndroidBundle.message(
                "not.resource.file.error", FileUtil.toSystemDependentName(resFile.getPath())));
      }

      for (ResourceElement element :
          AndroidResourceUtil.getValueResourcesFromElement(resourceType.getName(), resources)) {
        if (resourceName.equals(element.getName().getValue())) {
          return new ValidationInfo(
              "resource '"
                  + resourceName
                  + "' already exists in "
                  + FileUtil.toSystemDependentName(resFile.getPath()));
        }
      }
    }
    return null;
  }
    /**
     * Returns a map from name to resource types for all resources known to this library. This is
     * used to make sure that when the {@link #isPrivate(ResourceType, String)} query method is
     * called, it can tell the difference between a resource implicitly private by not being
     * declared as public and a resource unknown to this library (e.g. defined by a different
     * library or the user's own project resources.)
     *
     * @return a map from name to resource type for all resources in this library
     */
    @Nullable
    private Multimap<String, ResourceType> computeAllMap() {
      // getSymbolFile() is not defined in AndroidLibrary, only in the subclass LibraryBundle
      File symbolFile = new File(mLibrary.getPublicResources().getParentFile(), FN_RESOURCE_TEXT);
      if (!symbolFile.exists()) {
        return null;
      }

      try {
        List<String> lines = Files.readLines(symbolFile, Charsets.UTF_8);
        Multimap<String, ResourceType> result = ArrayListMultimap.create(lines.size(), 2);

        ResourceType previousType = null;
        String previousTypeString = "";
        int lineIndex = 1;
        final int count = lines.size();
        for (; lineIndex <= count; lineIndex++) {
          String line = lines.get(lineIndex - 1);

          if (line.startsWith("int ")) { // not int[] definitions for styleables
            // format is "int <type> <class> <name> <value>"
            int typeStart = 4;
            int typeEnd = line.indexOf(' ', typeStart);

            // Items are sorted by type, so we can avoid looping over types in
            // ResourceType.getEnum() for each line by sharing type in each section
            String typeString = line.substring(typeStart, typeEnd);
            ResourceType type;
            if (typeString.equals(previousTypeString)) {
              type = previousType;
            } else {
              type = ResourceType.getEnum(typeString);
              previousTypeString = typeString;
              previousType = type;
            }
            if (type == null) { // some newly introduced type
              continue;
            }

            int nameStart = typeEnd + 1;
            int nameEnd = line.indexOf(' ', nameStart);
            String name = line.substring(nameStart, nameEnd);
            result.put(name, type);
          }
        }
        return result;
      } catch (IOException ignore) {
      }
      return null;
    }
Ejemplo n.º 5
0
  /**
   * Returns the resources values matching a given {@link FolderConfiguration} for the current
   * project.
   *
   * @param referenceConfig the configuration that each value must match.
   * @return a map with guaranteed to contain an entry for each {@link ResourceType}
   */
  @NonNull
  protected final Map<ResourceType, Map<String, ResourceValue>> doGetConfiguredResources(
      @NonNull FolderConfiguration referenceConfig) {
    ensureInitialized();

    Map<ResourceType, Map<String, ResourceValue>> map =
        new EnumMap<ResourceType, Map<String, ResourceValue>>(ResourceType.class);

    for (ResourceType key : ResourceType.values()) {
      // get the local results and put them in the map
      map.put(key, getConfiguredResource(key, referenceConfig));
    }

    return map;
  }
  private void createNewResourceFile(ResourceType resourceType) {
    AndroidFacet facet = AndroidFacet.getInstance(myModule);
    XmlFile newFile =
        CreateResourceFileAction.createFileResource(
            facet, resourceType, null, null, null, true, null);

    if (newFile != null) {
      String name = newFile.getName();
      int index = name.lastIndexOf('.');
      if (index != -1) {
        name = name.substring(0, index);
      }
      myResultResourceName = "@" + resourceType.getName() + "/" + name;
      close(OK_EXIT_CODE);
    }
  }
    public ResourceGroup(ResourceType type, ResourceManager manager) {
      myType = type;

      final String resourceType = type.getName();

      Collection<String> resourceNames = manager.getValueResourceNames(resourceType);
      for (String resourceName : resourceNames) {
        myItems.add(new ResourceItem(this, resourceName, null, RESOURCE_ITEM_ICON));
      }
      final Set<String> fileNames = new HashSet<String>();

      manager.processFileResources(
          resourceType,
          new FileResourceProcessor() {
            @Override
            public boolean process(
                @NotNull VirtualFile resFile,
                @NotNull String resName,
                @NotNull String resFolderType) {
              if (fileNames.add(resName)) {
                myItems.add(
                    new ResourceItem(
                        ResourceGroup.this, resName, resFile, resFile.getFileType().getIcon()));
              }
              return true;
            }
          });

      if (type == ResourceType.ID) {
        for (String id : manager.getIds(true)) {
          if (!resourceNames.contains(id)) {
            myItems.add(new ResourceItem(this, id, null, RESOURCE_ITEM_ICON));
          }
        }
      }

      Collections.sort(
          myItems,
          new Comparator<ResourceItem>() {
            @Override
            public int compare(ResourceItem resource1, ResourceItem resource2) {
              return resource1.toString().compareTo(resource2.toString());
            }
          });
    }
    /**
     * Returns a map from name to applicable resource types where the presence of the type+name
     * combination means that the corresponding resource is explicitly public.
     *
     * <p>If the result is null, there is no {@code public.txt} definition for this library, so all
     * resources should be taken to be public.
     *
     * @return a map from name to resource type for public resources in this library
     */
    @Nullable
    private Multimap<String, ResourceType> computeVisibilityMap() {
      File publicResources = mLibrary.getPublicResources();
      if (!publicResources.exists()) {
        return null;
      }

      try {
        List<String> lines = Files.readLines(publicResources, Charsets.UTF_8);
        Multimap<String, ResourceType> result = ArrayListMultimap.create(lines.size(), 2);
        for (String line : lines) {
          // These files are written by code in MergedResourceWriter#postWriteAction
          // Format for each line: <type><space><name>\n
          // Therefore, we don't expect/allow variations in the format (we don't
          // worry about extra spaces needing to be trimmed etc)
          int index = line.indexOf(' ');
          if (index == -1 || line.isEmpty()) {
            continue;
          }

          String typeString = line.substring(0, index);
          ResourceType type = ResourceType.getEnum(typeString);
          if (type == null) {
            // This could in theory happen if in the future a new ResourceType is
            // introduced, and a newer version of the Gradle build system writes the
            // name of this type into the public.txt file, and an older version of
            // the IDE then attempts to read it. Just skip these symbols.
            continue;
          }
          String name = line.substring(index + 1);
          result.put(name, type);
        }
        return result;
      } catch (IOException ignore) {
      }
      return null;
    }
  /**
   * Reads the public.xml file in data/res/values/ for a given resource folder and builds up a map
   * of public resources.
   *
   * <p>This map is a subset of the full resource map that only contains framework resources that
   * are public.
   *
   * @param logger a logger to report issues to
   */
  public void loadPublicResources(@Nullable ILogger logger) {
    IAbstractFolder valueFolder = getResFolder().getFolder(SdkConstants.FD_RES_VALUES);
    if (valueFolder.exists() == false) {
      return;
    }

    IAbstractFile publicXmlFile = valueFolder.getFile("public.xml"); // $NON-NLS-1$
    if (publicXmlFile.exists()) {
      Reader reader = null;
      try {
        reader =
            new BufferedReader(new InputStreamReader(publicXmlFile.getContents(), Charsets.UTF_8));
        KXmlParser parser = new KXmlParser();
        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
        parser.setInput(reader);

        ResourceType lastType = null;
        String lastTypeName = "";
        while (true) {
          int event = parser.next();
          if (event == XmlPullParser.START_TAG) {
            // As of API 15 there are a number of "java-symbol" entries here
            if (!parser.getName().equals("public")) { // $NON-NLS-1$
              continue;
            }

            String name = null;
            String typeName = null;
            for (int i = 0, n = parser.getAttributeCount(); i < n; i++) {
              String attribute = parser.getAttributeName(i);

              if (attribute.equals("name")) { // $NON-NLS-1$
                name = parser.getAttributeValue(i);
                if (typeName != null) {
                  // Skip id attribute processing
                  break;
                }
              } else if (attribute.equals("type")) { // $NON-NLS-1$
                typeName = parser.getAttributeValue(i);
              }
            }

            if (name != null && typeName != null) {
              ResourceType type = null;
              if (typeName.equals(lastTypeName)) {
                type = lastType;
              } else {
                type = ResourceType.getEnum(typeName);
                lastType = type;
                lastTypeName = typeName;
              }
              if (type != null) {
                ResourceItem match = null;
                Map<String, ResourceItem> map = mResourceMap.get(type);
                if (map != null) {
                  match = map.get(name);
                }

                if (match != null) {
                  List<ResourceItem> publicList = mPublicResourceMap.get(type);
                  if (publicList == null) {
                    // Pick initial size for the list to hold the public
                    // resources. We could just use map.size() here,
                    // but they're usually much bigger; for example,
                    // in one platform version, there are 1500 drawables
                    // and 1200 strings but only 175 and 25 public ones
                    // respectively.
                    int size;
                    switch (type) {
                      case STYLE:
                        size = 500;
                        break;
                      case ATTR:
                        size = 1000;
                        break;
                      case DRAWABLE:
                        size = 200;
                        break;
                      case ID:
                        size = 50;
                        break;
                      case LAYOUT:
                      case COLOR:
                      case STRING:
                      case ANIM:
                      case INTERPOLATOR:
                        size = 30;
                        break;
                      default:
                        size = 10;
                        break;
                    }
                    publicList = new ArrayList<ResourceItem>(size);
                    mPublicResourceMap.put(type, publicList);
                  }

                  publicList.add(match);
                } else {
                  // log that there's a public resource that doesn't actually
                  // exist?
                }
              } else {
                // log that there was a reference to a typo that doesn't actually
                // exist?
              }
            }
          } else if (event == XmlPullParser.END_DOCUMENT) {
            break;
          }
        }
      } catch (Exception e) {
        if (logger != null) {
          logger.error(e, "Can't read and parse public attribute list");
        }
      } finally {
        if (reader != null) {
          try {
            reader.close();
          } catch (IOException e) {
            // Nothing to be done here - we don't care if it closed or not.
          }
        }
      }
    }

    // put unmodifiable list for all res type in the public resource map
    // this will simplify access
    for (ResourceType type : ResourceType.values()) {
      List<ResourceItem> list = mPublicResourceMap.get(type);
      if (list == null) {
        list = Collections.emptyList();
      } else {
        list = Collections.unmodifiableList(list);
      }

      // put the new list in the map
      mPublicResourceMap.put(type, list);
    }
  }
 @Override
 public String toString() {
   return myType.getDisplayName();
 }
 public String getName() {
   return myType.getName();
 }
  public static void collectAllResources(
      @NotNull final AndroidFacet facet, final Set<ResourceEntry> resourceSet) {
    final LocalResourceManager manager = facet.getLocalResourceManager();
    for (final String resType : ResourceType.getNames()) {
      for (final ResourceElement element : manager.getValueResources(resType)) {
        ApplicationManager.getApplication()
            .runReadAction(
                new Runnable() {
                  @Override
                  public void run() {
                    if (!element.isValid()
                        || facet.getModule().isDisposed()
                        || facet.getModule().getProject().isDisposed()) {
                      return;
                    }
                    final String name = element.getName().getValue();

                    if (name != null) {
                      resourceSet.add(new ResourceEntry(resType, name));
                    }
                  }
                });
      }
    }

    for (final Resources resources : manager.getResourceElements()) {
      ApplicationManager.getApplication()
          .runReadAction(
              new Runnable() {
                @Override
                public void run() {
                  if (!resources.isValid()
                      || facet.getModule().isDisposed()
                      || facet.getModule().getProject().isDisposed()) {
                    return;
                  }

                  for (final Attr attr : resources.getAttrs()) {
                    final String name = attr.getName().getValue();

                    if (name != null) {
                      resourceSet.add(new ResourceEntry(ResourceType.ATTR.getName(), name));
                    }
                  }

                  for (final DeclareStyleable styleable : resources.getDeclareStyleables()) {
                    final String name = styleable.getName().getValue();

                    if (name != null) {
                      resourceSet.add(
                          new ResourceEntry(ResourceType.DECLARE_STYLEABLE.getName(), name));
                    }
                  }
                }
              });
    }

    ApplicationManager.getApplication()
        .runReadAction(
            new Runnable() {
              @Override
              public void run() {
                if (facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) {
                  return;
                }

                for (String id : manager.getIds()) {
                  resourceSet.add(new ResourceEntry(ResourceType.ID.getName(), id));
                }
              }
            });
    final HashSet<VirtualFile> visited = new HashSet<VirtualFile>();

    for (VirtualFile subdir : manager.getResourceSubdirs(null)) {
      final HashSet<VirtualFile> resourceFiles = new HashSet<VirtualFile>();
      AndroidUtils.collectFiles(subdir, visited, resourceFiles);

      for (VirtualFile file : resourceFiles) {
        resourceSet.add(new ResourceEntry(subdir.getName(), file.getName()));
      }
    }
  }