1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php 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 package com.android.ide.eclipse.adt.internal.wizards.templates; 17 18 import static com.android.SdkConstants.FD_EXTRAS; 19 import static com.android.SdkConstants.FD_TEMPLATES; 20 import static com.android.SdkConstants.FD_TOOLS; 21 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TEMPLATE_XML; 22 23 import com.android.annotations.NonNull; 24 import com.android.annotations.Nullable; 25 import com.android.ide.eclipse.adt.AdtPlugin; 26 import com.android.ide.eclipse.adt.AdtUtils; 27 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; 28 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; 29 import com.google.common.base.Charsets; 30 import com.google.common.collect.Maps; 31 import com.google.common.io.Files; 32 33 import org.w3c.dom.Document; 34 35 import java.io.File; 36 import java.io.IOException; 37 import java.util.ArrayList; 38 import java.util.Collections; 39 import java.util.Comparator; 40 import java.util.List; 41 import java.util.Map; 42 43 /** Handles locating templates and providing template metadata */ 44 public class TemplateManager { TemplateManager()45 TemplateManager() { 46 } 47 48 /** @return the root folder containing templates */ 49 @Nullable getTemplateRootFolder()50 public static File getTemplateRootFolder() { 51 String location = AdtPrefs.getPrefs().getOsSdkFolder(); 52 if (location != null) { 53 File folder = new File(location, FD_TOOLS + File.separator + FD_TEMPLATES); 54 if (folder.isDirectory()) { 55 return folder; 56 } 57 } 58 59 return null; 60 } 61 62 /** @return the root folder containing extra templates */ 63 @NonNull getExtraTemplateRootFolders()64 public static List<File> getExtraTemplateRootFolders() { 65 List<File> folders = new ArrayList<File>(); 66 String location = AdtPrefs.getPrefs().getOsSdkFolder(); 67 if (location != null) { 68 File extras = new File(location, FD_EXTRAS); 69 if (extras.isDirectory()) { 70 for (File vendor : AdtUtils.listFiles(extras)) { 71 if (!vendor.isDirectory()) { 72 continue; 73 } 74 for (File pkg : AdtUtils.listFiles(vendor)) { 75 if (pkg.isDirectory()) { 76 File folder = new File(pkg, FD_TEMPLATES); 77 if (folder.isDirectory()) { 78 folders.add(folder); 79 } 80 } 81 } 82 } 83 84 // Legacy 85 File folder = new File(extras, FD_TEMPLATES); 86 if (folder.isDirectory()) { 87 folders.add(folder); 88 } 89 } 90 } 91 92 return folders; 93 } 94 95 /** 96 * Returns a template file under the given root, if it exists 97 * 98 * @param root the root folder 99 * @param relativePath the relative path 100 * @return a template file under the given root, if it exists 101 */ 102 @Nullable getTemplateLocation(@onNull File root, @NonNull String relativePath)103 public static File getTemplateLocation(@NonNull File root, @NonNull String relativePath) { 104 File templateRoot = getTemplateRootFolder(); 105 if (templateRoot != null) { 106 String rootPath = root.getPath(); 107 File templateFile = new File(templateRoot, 108 rootPath.replace('/', File.separatorChar) + File.separator 109 + relativePath.replace('/', File.separatorChar)); 110 if (templateFile.exists()) { 111 return templateFile; 112 } 113 } 114 115 return null; 116 } 117 118 /** 119 * Returns a template file under one of the available roots, if it exists 120 * 121 * @param relativePath the relative path 122 * @return a template file under one of the available roots, if it exists 123 */ 124 @Nullable getTemplateLocation(@onNull String relativePath)125 public static File getTemplateLocation(@NonNull String relativePath) { 126 File templateRoot = getTemplateRootFolder(); 127 if (templateRoot != null) { 128 File templateFile = new File(templateRoot, 129 relativePath.replace('/', File.separatorChar)); 130 if (templateFile.exists()) { 131 return templateFile; 132 } 133 } 134 135 return null; 136 137 } 138 139 /** 140 * Returns all the templates with the given prefix 141 * 142 * @param folder the folder prefix 143 * @return the available templates 144 */ 145 @NonNull getTemplates(@onNull String folder)146 List<File> getTemplates(@NonNull String folder) { 147 List<File> templates = new ArrayList<File>(); 148 Map<String, File> templateNames = Maps.newHashMap(); 149 File root = getTemplateRootFolder(); 150 if (root != null) { 151 File[] files = new File(root, folder).listFiles(); 152 if (files != null) { 153 for (File file : files) { 154 if (file.isDirectory()) { // Avoid .DS_Store etc 155 templates.add(file); 156 templateNames.put(file.getName(), file); 157 } 158 } 159 } 160 } 161 162 // Add in templates from extras/ as well. 163 for (File extra : getExtraTemplateRootFolders()) { 164 File[] files = new File(extra, folder).listFiles(); 165 if (files != null) { 166 for (File file : files) { 167 if (file.isDirectory()) { 168 File replaces = templateNames.get(file.getName()); 169 if (replaces != null) { 170 int compare = compareTemplates(replaces, file); 171 if (compare > 0) { 172 int index = templates.indexOf(replaces); 173 if (index != -1) { 174 templates.set(index, file); 175 } else { 176 templates.add(file); 177 } 178 } 179 } else { 180 templates.add(file); 181 } 182 } 183 } 184 } 185 } 186 187 // Sort by file name (not path as is File's default) 188 if (templates.size() > 1) { 189 Collections.sort(templates, new Comparator<File>() { 190 @Override 191 public int compare(File file1, File file2) { 192 return file1.getName().compareTo(file2.getName()); 193 } 194 }); 195 } 196 197 return templates; 198 } 199 200 /** 201 * Compare two files, and return the one with the HIGHEST revision, and if 202 * the same, most recently modified 203 */ compareTemplates(File file1, File file2)204 private int compareTemplates(File file1, File file2) { 205 TemplateMetadata template1 = getTemplate(file1); 206 TemplateMetadata template2 = getTemplate(file2); 207 208 if (template1 == null) { 209 return 1; 210 } else if (template2 == null) { 211 return -1; 212 } else { 213 int delta = template2.getRevision() - template1.getRevision(); 214 if (delta == 0) { 215 delta = (int) (file2.lastModified() - file1.lastModified()); 216 } 217 return delta; 218 } 219 } 220 221 /** Cache for {@link #getTemplate()} */ 222 private Map<File, TemplateMetadata> mTemplateMap; 223 224 @Nullable getTemplate(File templateDir)225 TemplateMetadata getTemplate(File templateDir) { 226 if (mTemplateMap != null) { 227 TemplateMetadata metadata = mTemplateMap.get(templateDir); 228 if (metadata != null) { 229 return metadata; 230 } 231 } else { 232 mTemplateMap = Maps.newHashMap(); 233 } 234 235 try { 236 File templateFile = new File(templateDir, TEMPLATE_XML); 237 if (templateFile.isFile()) { 238 String xml = Files.toString(templateFile, Charsets.UTF_8); 239 Document doc = DomUtilities.parseDocument(xml, true); 240 if (doc != null && doc.getDocumentElement() != null) { 241 TemplateMetadata metadata = new TemplateMetadata(doc); 242 mTemplateMap.put(templateDir, metadata); 243 return metadata; 244 } 245 } 246 } catch (IOException e) { 247 AdtPlugin.log(e, null); 248 } 249 250 return null; 251 } 252 } 253