Home | History | Annotate | Download | only in resources
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.common.resources;
     18 
     19 import com.android.annotations.VisibleForTesting;
     20 import com.android.annotations.VisibleForTesting.Visibility;
     21 import com.android.ide.common.resources.configuration.Configurable;
     22 import com.android.ide.common.resources.configuration.FolderConfiguration;
     23 import com.android.io.IAbstractFile;
     24 import com.android.io.IAbstractFolder;
     25 import com.android.resources.FolderTypeRelationship;
     26 import com.android.resources.ResourceFolderType;
     27 import com.android.resources.ResourceType;
     28 
     29 import java.util.ArrayList;
     30 import java.util.Collection;
     31 import java.util.List;
     32 
     33 /**
     34  * Resource Folder class. Contains list of {@link ResourceFile}s,
     35  * the {@link FolderConfiguration}, and a link to the {@link IAbstractFolder} object.
     36  */
     37 public final class ResourceFolder implements Configurable {
     38     final ResourceFolderType mType;
     39     final FolderConfiguration mConfiguration;
     40     IAbstractFolder mFolder;
     41     ArrayList<ResourceFile> mFiles = null;
     42     private final ResourceRepository mRepository;
     43 
     44 
     45     /**
     46      * Creates a new {@link ResourceFolder}
     47      * @param type The type of the folder
     48      * @param config The configuration of the folder
     49      * @param folder The associated {@link IAbstractFolder} object.
     50      * @param repository The associated {@link ResourceRepository}
     51      */
     52     protected ResourceFolder(ResourceFolderType type, FolderConfiguration config,
     53             IAbstractFolder folder, ResourceRepository repository) {
     54         mType = type;
     55         mConfiguration = config;
     56         mFolder = folder;
     57         mRepository = repository;
     58     }
     59 
     60     /**
     61      * Processes a file and adds it to its parent folder resource.
     62      *
     63      * @param file the underlying resource file.
     64      * @param kind the file change kind.
     65      * @param context a context object with state for the current update, such
     66      *            as a place to stash errors encountered
     67      * @return the {@link ResourceFile} that was created.
     68      */
     69     public ResourceFile processFile(IAbstractFile file, ResourceDeltaKind kind,
     70             ScanningContext context) {
     71         // look for this file if it's already been created
     72         ResourceFile resFile = getFile(file);
     73 
     74         if (resFile == null) {
     75             if (kind != ResourceDeltaKind.REMOVED) {
     76                 // create a ResourceFile for it.
     77 
     78                 // check if that's a single or multi resource type folder. For now we define this by
     79                 // the number of possible resource type output by files in the folder.
     80                 // We have a special case for layout/menu folders which can also generate IDs.
     81                 // This does
     82                 // not make the difference between several resource types from a single file or
     83                 // the ability to have 2 files in the same folder generating 2 different types of
     84                 // resource. The former is handled by MultiResourceFile properly while we don't
     85                 // handle the latter. If we were to add this behavior we'd have to change this call.
     86                 List<ResourceType> types = FolderTypeRelationship.getRelatedResourceTypes(mType);
     87 
     88                 if (types.size() == 1) {
     89                     resFile = new SingleResourceFile(file, this);
     90                 } else if (types.contains(ResourceType.LAYOUT)) {
     91                     resFile = new IdGeneratingResourceFile(file, this, ResourceType.LAYOUT);
     92                 } else if (types.contains(ResourceType.MENU)) {
     93                     resFile = new IdGeneratingResourceFile(file, this, ResourceType.MENU);
     94                 } else {
     95                     resFile = new MultiResourceFile(file, this);
     96                 }
     97 
     98                 resFile.load(context);
     99 
    100                 // add it to the folder
    101                 addFile(resFile);
    102             }
    103         } else {
    104             if (kind == ResourceDeltaKind.REMOVED) {
    105                 removeFile(resFile, context);
    106             } else {
    107                 resFile.update(context);
    108             }
    109         }
    110 
    111         return resFile;
    112     }
    113 
    114 
    115     /**
    116      * Adds a {@link ResourceFile} to the folder.
    117      * @param file The {@link ResourceFile}.
    118      */
    119     @VisibleForTesting(visibility=Visibility.PROTECTED)
    120     public void addFile(ResourceFile file) {
    121         if (mFiles == null) {
    122             mFiles = new ArrayList<ResourceFile>();
    123         }
    124 
    125         mFiles.add(file);
    126     }
    127 
    128     protected void removeFile(ResourceFile file, ScanningContext context) {
    129         file.dispose(context);
    130         mFiles.remove(file);
    131     }
    132 
    133     protected void dispose(ScanningContext context) {
    134         if (mFiles != null) {
    135             for (ResourceFile file : mFiles) {
    136                 file.dispose(context);
    137             }
    138 
    139             mFiles.clear();
    140         }
    141     }
    142 
    143     /**
    144      * Returns the {@link IAbstractFolder} associated with this object.
    145      */
    146     public IAbstractFolder getFolder() {
    147         return mFolder;
    148     }
    149 
    150     /**
    151      * Returns the {@link ResourceFolderType} of this object.
    152      */
    153     public ResourceFolderType getType() {
    154         return mType;
    155     }
    156 
    157     public ResourceRepository getRepository() {
    158         return mRepository;
    159     }
    160 
    161     /**
    162      * Returns the list of {@link ResourceType}s generated by the files inside this folder.
    163      */
    164     public Collection<ResourceType> getResourceTypes() {
    165         ArrayList<ResourceType> list = new ArrayList<ResourceType>();
    166 
    167         if (mFiles != null) {
    168             for (ResourceFile file : mFiles) {
    169                 Collection<ResourceType> types = file.getResourceTypes();
    170 
    171                 // loop through those and add them to the main list,
    172                 // if they are not already present
    173                 for (ResourceType resType : types) {
    174                     if (list.indexOf(resType) == -1) {
    175                         list.add(resType);
    176                     }
    177                 }
    178             }
    179         }
    180 
    181         return list;
    182     }
    183 
    184     public FolderConfiguration getConfiguration() {
    185         return mConfiguration;
    186     }
    187 
    188     /**
    189      * Returns whether the folder contains a file with the given name.
    190      * @param name the name of the file.
    191      */
    192     public boolean hasFile(String name) {
    193         return mFolder.hasFile(name);
    194     }
    195 
    196     /**
    197      * Returns the {@link ResourceFile} matching a {@link IAbstractFile} object.
    198      * @param file The {@link IAbstractFile} object.
    199      * @return the {@link ResourceFile} or null if no match was found.
    200      */
    201     private ResourceFile getFile(IAbstractFile file) {
    202         if (mFiles != null) {
    203             for (ResourceFile f : mFiles) {
    204                 if (f.getFile().equals(file)) {
    205                     return f;
    206                 }
    207             }
    208         }
    209         return null;
    210     }
    211 
    212     /**
    213      * Returns the {@link ResourceFile} matching a given name.
    214      * @param filename The name of the file to return.
    215      * @return the {@link ResourceFile} or <code>null</code> if no match was found.
    216      */
    217     public ResourceFile getFile(String filename) {
    218         if (mFiles != null) {
    219             for (ResourceFile f : mFiles) {
    220                 if (f.getFile().getName().equals(filename)) {
    221                     return f;
    222                 }
    223             }
    224         }
    225         return null;
    226     }
    227 
    228     /**
    229      * Returns whether a file in the folder is generating a resource of a specified type.
    230      * @param type The {@link ResourceType} being looked up.
    231      */
    232     public boolean hasResources(ResourceType type) {
    233         // Check if the folder type is able to generate resource of the type that was asked.
    234         // this is a first check to avoid going through the files.
    235         List<ResourceFolderType> folderTypes = FolderTypeRelationship.getRelatedFolders(type);
    236 
    237         boolean valid = false;
    238         for (ResourceFolderType rft : folderTypes) {
    239             if (rft == mType) {
    240                 valid = true;
    241                 break;
    242             }
    243         }
    244 
    245         if (valid) {
    246             if (mFiles != null) {
    247                 for (ResourceFile f : mFiles) {
    248                     if (f.hasResources(type)) {
    249                         return true;
    250                     }
    251                 }
    252             }
    253         }
    254         return false;
    255     }
    256 
    257     @Override
    258     public String toString() {
    259         return mFolder.toString();
    260     }
    261 }
    262