17dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye/* 27dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Copyright (C) 2012 The Android Open Source Project 37dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * 47dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 57dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * you may not use this file except in compliance with the License. 67dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * You may obtain a copy of the License at 77dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * 87dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * http://www.eclipse.org/org/documents/epl-v10.php 97dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * 107dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Unless required by applicable law or agreed to in writing, software 117dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS, 127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * See the License for the specific language governing permissions and 147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * limitations under the License. 157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyepackage com.android.ide.eclipse.adt.internal.wizards.templates; 177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 180386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Mollimport static com.android.SdkConstants.DOT_AIDL; 1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_FTL; 2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_JAVA; 2112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_RS; 2212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_SVG; 2312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_TXT; 2412d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.DOT_XML; 2512d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.EXT_XML; 260386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Mollimport static com.android.SdkConstants.FD_NATIVE_LIBS; 27dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbyeimport static com.android.ide.eclipse.adt.internal.wizards.templates.InstallDependencyPage.SUPPORT_LIBRARY_NAME; 286d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbyeimport static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateManager.getTemplateRootFolder; 297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3081cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport com.android.SdkConstants; 317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.annotations.NonNull; 327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.annotations.Nullable; 337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.ide.eclipse.adt.AdtPlugin; 347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.ide.eclipse.adt.AdtUtils; 35b8397698e2834ed8af03c1bff7d570aff0e2f5bbRaphael Mollimport com.android.ide.eclipse.adt.internal.actions.AddSupportJarAction; 367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatPreferences; 377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; 387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.formatting.XmlPrettyPrinter; 397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; 4057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 410386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Mollimport com.android.ide.eclipse.adt.internal.sdk.AdtManifestMergeCallback; 427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.manifmerger.ManifestMerger; 431311018325c75993ae84183b41d3fd915bce965dRaphael Mollimport com.android.manifmerger.MergerLog; 447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.resources.ResourceFolderType; 451fb460987f7d832adf12290f41448d0c16a95972Siva Velusamyimport com.android.utils.SdkUtils; 467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.google.common.base.Charsets; 47dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbyeimport com.google.common.collect.Lists; 487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.google.common.io.Files; 497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport freemarker.cache.TemplateLoader; 517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport freemarker.template.Configuration; 527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport freemarker.template.DefaultObjectWrapper; 537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport freemarker.template.Template; 547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport freemarker.template.TemplateException; 557dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 56802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.core.resources.IFile; 57802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.core.resources.IProject; 58802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.core.resources.IResource; 5957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.core.runtime.CoreException; 60802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.core.runtime.IPath; 617f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbyeimport org.eclipse.core.runtime.IStatus; 627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.eclipse.core.runtime.Path; 637f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbyeimport org.eclipse.core.runtime.Status; 6457d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.jdt.core.IJavaProject; 6557d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.jdt.core.JavaCore; 6657d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.jdt.core.ToolFactory; 6757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.jdt.core.formatter.CodeFormatter; 687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.eclipse.jface.dialogs.MessageDialog; 6957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.jface.text.IDocument; 70802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.ltk.core.refactoring.Change; 71802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.ltk.core.refactoring.NullChange; 72802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.ltk.core.refactoring.TextFileChange; 737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.eclipse.swt.SWT; 74802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.text.edits.InsertEdit; 75802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.text.edits.MultiTextEdit; 76802de810020fba3f86282cd1d66597a2a41698e3Tor Norbyeimport org.eclipse.text.edits.ReplaceEdit; 7757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbyeimport org.eclipse.text.edits.TextEdit; 787f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbyeimport org.osgi.framework.Constants; 797f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbyeimport org.osgi.framework.Version; 807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.w3c.dom.Document; 817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.w3c.dom.Element; 827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.w3c.dom.Node; 837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.w3c.dom.NodeList; 847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.xml.sax.Attributes; 857dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.xml.sax.SAXException; 867dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport org.xml.sax.helpers.DefaultHandler; 877dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.ByteArrayInputStream; 897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.File; 907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.IOException; 917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.InputStreamReader; 927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.Reader; 937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.StringWriter; 947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.io.Writer; 957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.net.URL; 967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.util.ArrayList; 977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.util.Arrays; 987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.util.HashMap; 997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.util.List; 1007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport java.util.Map; 1017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport javax.xml.parsers.SAXParser; 1037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport javax.xml.parsers.SAXParserFactory; 1047dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1057dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye/** 1067dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Handler which manages instantiating FreeMarker templates, copying resources 1077dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * and merging into existing files 1087dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 1097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeclass TemplateHandler { 110c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye /** Highest supported format; templates with a higher number will be skipped 111c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * <p> 112c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * <ul> 113c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * <li> 1: Initial format, supported by ADT 20 and up. 114c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * <li> 2: ADT 21 and up. Boolean variables that have a default value and are not 115c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * edited by the user would end up as strings in ADT 20; now they are always 116c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * proper Booleans. Templates which rely on this should specify format >= 2. 11733c1e883ce229219268bb5584d4769106c736c39Tor Norbye * <li> 3: The wizard infrastructure passes the {@code isNewProject} boolean variable 11833c1e883ce229219268bb5584d4769106c736c39Tor Norbye * to indicate whether a wizard is created as part of a new blank project 119c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye * </ul> 120c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye */ 12133c1e883ce229219268bb5584d4769106c736c39Tor Norbye static final int CURRENT_FORMAT = 3; 1227f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye 1237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 1247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Special marker indicating that this path refers to the special shared 1257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * resource directory rather than being somewhere inside the root/ directory 1267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * where all template specific resources are found 1277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 1287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private static final String VALUE_TEMPLATE_DIR = "$TEMPLATEDIR"; //$NON-NLS-1$ 1297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 1317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Directory within the template which contains the resources referenced 1327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * from the template.xml file 1337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 1347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private static final String DATA_ROOT = "root"; //$NON-NLS-1$ 1357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 1377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Shared resource directory containing common resources shared among 1387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * multiple templates 1397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 14056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye private static final String RESOURCE_ROOT = "resources"; //$NON-NLS-1$ 1417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Reserved filename which describes each template */ 1437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TEMPLATE_XML = "template.xml"; //$NON-NLS-1$ 1447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Various tags and attributes used in the template metadata files - template.xml, 1467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // globals.xml.ftl, recipe.xml.ftl, etc. 1477dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_MERGE = "merge"; //$NON-NLS-1$ 1497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_EXECUTE = "execute"; //$NON-NLS-1$ 1507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_GLOBALS = "globals"; //$NON-NLS-1$ 1517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_GLOBAL = "global"; //$NON-NLS-1$ 1527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_PARAMETER = "parameter"; //$NON-NLS-1$ 1537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_COPY = "copy"; //$NON-NLS-1$ 1547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_INSTANTIATE = "instantiate"; //$NON-NLS-1$ 1557dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String TAG_OPEN = "open"; //$NON-NLS-1$ 156fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye static final String TAG_THUMB = "thumb"; //$NON-NLS-1$ 157fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye static final String TAG_THUMBS = "thumbs"; //$NON-NLS-1$ 1587f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye static final String TAG_DEPENDENCY = "dependency"; //$NON-NLS-1$ 159279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String TAG_ICONS = "icons"; //$NON-NLS-1$ 1607f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye static final String ATTR_FORMAT = "format"; //$NON-NLS-1$ 1617f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye static final String ATTR_REVISION = "revision"; //$NON-NLS-1$ 1627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_VALUE = "value"; //$NON-NLS-1$ 1637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_DEFAULT = "default"; //$NON-NLS-1$ 1647dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_SUGGEST = "suggest"; //$NON-NLS-1$ 1657dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_ID = "id"; //$NON-NLS-1$ 1667dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_NAME = "name"; //$NON-NLS-1$ 1677dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_DESCRIPTION = "description";//$NON-NLS-1$ 1687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_TYPE = "type"; //$NON-NLS-1$ 1697dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_HELP = "help"; //$NON-NLS-1$ 1707dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_FILE = "file"; //$NON-NLS-1$ 1717dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_TO = "to"; //$NON-NLS-1$ 1727dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_FROM = "from"; //$NON-NLS-1$ 1737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final String ATTR_CONSTRAINTS = "constraints";//$NON-NLS-1$ 174279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_BACKGROUND = "background"; //$NON-NLS-1$ 175279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_FOREGROUND = "foreground"; //$NON-NLS-1$ 176279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_SHAPE = "shape"; //$NON-NLS-1$ 177279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_TRIM = "trim"; //$NON-NLS-1$ 178279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_PADDING = "padding"; //$NON-NLS-1$ 179279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_SOURCE_TYPE = "source"; //$NON-NLS-1$ 180279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_CLIPART_NAME = "clipartName";//$NON-NLS-1$ 181279445ad4561895db41309681de8dd1544d0ae22Tor Norbye static final String ATTR_TEXT = "text"; //$NON-NLS-1$ 1827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 18356afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye static final String CATEGORY_ACTIVITIES = "activities";//$NON-NLS-1$ 18456afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye static final String CATEGORY_PROJECTS = "projects"; //$NON-NLS-1$ 18556afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye static final String CATEGORY_OTHER = "other"; //$NON-NLS-1$ 18656afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye 18756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye 1887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Default padding to apply in wizards around the thumbnail preview images */ 1897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final int PREVIEW_PADDING = 10; 1907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Default width to scale thumbnail preview images in wizards to */ 1927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static final int PREVIEW_WIDTH = 200; 1937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 1957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * List of files to open after the wizard has been created (these are 1967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * identified by {@link #TAG_OPEN} elements in the recipe file 1977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 1987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private final List<String> mOpen = Lists.newArrayList(); 1997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Path to the directory containing the templates */ 20156afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye @NonNull 2027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private final File mRootPath; 2037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 204802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye /** The changes being processed by the template handler */ 205802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private List<Change> mMergeChanges; 206802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private List<Change> mTextChanges; 207802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private List<Change> mOtherChanges; 208802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 209802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye /** The project to write the template into */ 210802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private IProject mProject; 211802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 2127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** The template loader which is responsible for finding (and sharing) template files */ 2137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private final MyTemplateLoader mLoader; 2147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Agree to all file-overwrites from now on? */ 2167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private boolean mYesToAll = false; 2177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Is writing the template cancelled? */ 2197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private boolean mNoToAll = false; 2207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 2227dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Should files that we merge contents into be backed up? If yes, will 2237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * create emacs-style tilde-file backups (filename.xml~) 2247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 2257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private boolean mBackupMergedFiles = true; 2267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 227fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye /** 228fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye * Template metadata 229fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye */ 230fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye private TemplateMetadata mTemplate; 231fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye 2326d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye private TemplateManager mManager; 2336d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye 2347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Creates a new {@link TemplateHandler} for the given root path */ 2357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static TemplateHandler createFromPath(File rootPath) { 2366d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye return new TemplateHandler(rootPath, new TemplateManager()); 2377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 2387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 23956afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye /** Creates a new {@link TemplateHandler} for the template name, which should 24056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye * be relative to the templates directory */ 2416d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye static TemplateHandler createFromName(String category, String name) { 2426d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye TemplateManager manager = new TemplateManager(); 2436d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye 2446d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye // Use the TemplateManager iteration which should merge contents between the 2456d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye // extras/templates/ and tools/templates folders and pick the most recent version 2466d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye List<File> templates = manager.getTemplates(category); 2476d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye for (File file : templates) { 2486d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye if (file.getName().equals(name) && category.equals(file.getParentFile().getName())) { 2496d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye return new TemplateHandler(file, manager); 2506d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye } 2516d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye } 2526d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye 2536d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye return new TemplateHandler(new File(getTemplateRootFolder(), 2546d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye category + File.separator + name), manager); 25556afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye } 25656afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye 2576d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye private TemplateHandler(File rootPath, TemplateManager manager) { 2587dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mRootPath = rootPath; 2596d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye mManager = manager; 2607dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mLoader = new MyTemplateLoader(); 2617dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mLoader.setPrefix(mRootPath.getPath()); 2627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 2637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2646d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye public TemplateManager getManager() { 2656d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye return mManager; 2666d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye } 2676d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye 2687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void setBackupMergedFiles(boolean backupMergedFiles) { 2697dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mBackupMergedFiles = backupMergedFiles; 2707dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 2717dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 272802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye @NonNull 273802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye public List<Change> render(IProject project, Map<String, Object> args) { 274802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mOpen.clear(); 275802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 276802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mProject = project; 277802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mMergeChanges = new ArrayList<Change>(); 278802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mTextChanges = new ArrayList<Change>(); 279802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mOtherChanges = new ArrayList<Change>(); 2807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Render the instruction list template. 2827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Map<String, Object> paramMap = createParameterMap(args); 2837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Configuration freemarker = new Configuration(); 2847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye freemarker.setObjectWrapper(new DefaultObjectWrapper()); 2857dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye freemarker.setTemplateLoader(mLoader); 2867dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 287802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye processVariables(freemarker, TEMPLATE_XML, paramMap); 288802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 289802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye // Add the changes in the order where merges are shown first, then text files, 290802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye // and finally other files (like jars and icons which don't have previews). 291802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye List<Change> changes = new ArrayList<Change>(); 292802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye changes.addAll(mMergeChanges); 293802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye changes.addAll(mTextChanges); 294802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye changes.addAll(mOtherChanges); 295802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye return changes; 2967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 2977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 2987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Map<String, Object> createParameterMap(Map<String, Object> args) { 2997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye final Map<String, Object> paramMap = createBuiltinMap(); 3007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Wizard parameters supplied by user, specific to this template 3027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.putAll(args); 3037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3047dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return paramMap; 3057dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3067dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3077dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Data model for the templates */ 3087dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye static Map<String, Object> createBuiltinMap() { 3097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Create the data model. 3107dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye final Map<String, Object> paramMap = new HashMap<String, Object>(); 3117dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Builtin conversion methods 3137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put("slashedPackageName", new FmSlashedPackageNameMethod()); //$NON-NLS-1$ 3147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put("camelCaseToUnderscore", new FmCamelCaseToUnderscoreMethod()); //$NON-NLS-1$ 3157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put("underscoreToCamelCase", new FmUnderscoreToCamelCaseMethod()); //$NON-NLS-1$ 3167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put("activityToLayout", new FmActivityToLayoutMethod()); //$NON-NLS-1$ 3177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put("layoutToActivity", new FmLayoutToActivityMethod()); //$NON-NLS-1$ 318c2548413ad5c85a5e2863fb178f478a9fad3d0f6Tor Norbye paramMap.put("classToResource", new FmClassNameToResourceMethod()); //$NON-NLS-1$ 319454f0e05d3e202320b0cd7bc176360458e88658eTor Norbye paramMap.put("escapeXmlAttribute", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ 320454f0e05d3e202320b0cd7bc176360458e88658eTor Norbye paramMap.put("escapeXmlText", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ 321454f0e05d3e202320b0cd7bc176360458e88658eTor Norbye paramMap.put("escapeXmlString", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ 322454f0e05d3e202320b0cd7bc176360458e88658eTor Norbye paramMap.put("extractLetters", new FmExtractLettersMethod()); //$NON-NLS-1$ 3237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // This should be handled better: perhaps declared "required packages" as part of the 3257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // inputs? (It would be better if we could conditionally disable template based 3267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // on availability) 3277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Map<String, String> builtin = new HashMap<String, String>(); 3287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye builtin.put("templatesRes", VALUE_TEMPLATE_DIR); //$NON-NLS-1$ 3297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put("android", builtin); //$NON-NLS-1$ 3307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return paramMap; 3327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Nullable 335fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye public TemplateMetadata getTemplate() { 336fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye if (mTemplate == null) { 3376d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye mTemplate = mManager.getTemplate(mRootPath); 3387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 339fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye 340fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye return mTemplate; 3417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 343fd54b68d77bc90d5c607517c27bd7a30a2a8a57aTor Norbye @NonNull 3447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public String getResourcePath(String templateName) { 3457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return new File(mRootPath.getPath(), templateName).getPath(); 3467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3477dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3486d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye /** 3497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Load a text resource for the given relative path within the template 3507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * 3517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * @param relativePath relative path within the template 3527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * @return the string contents of the template text file 3537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 3547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Nullable 3557dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public String readTemplateTextResource(@NonNull String relativePath) { 35656afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye try { 35756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return Files.toString(new File(mRootPath, 35856afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye relativePath.replace('/', File.separatorChar)), Charsets.UTF_8); 35956afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye } catch (IOException e) { 36056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye AdtPlugin.log(e, null); 36156afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return null; 3627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3647dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3657dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Nullable 3667dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public String readTemplateTextResource(@NonNull File file) { 36756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye assert file.isAbsolute(); 36856afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye try { 36956afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return Files.toString(file, Charsets.UTF_8); 37056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye } catch (IOException e) { 37156afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye AdtPlugin.log(e, null); 37256afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return null; 3737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3747dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3757dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3767dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 3777dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Reads the contents of a resource 3787dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * 3797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * @param relativePath the path relative to the template directory 3807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * @return the binary data read from the file 3817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 3827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Nullable 3837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public byte[] readTemplateResource(@NonNull String relativePath) { 38456afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye try { 38556afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return Files.toByteArray(new File(mRootPath, relativePath)); 38656afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye } catch (IOException e) { 38756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye AdtPlugin.log(e, null); 38856afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return null; 3897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 3917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 3927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Read the given FreeMarker file and process the variable definitions */ 3937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private void processVariables(final Configuration freemarker, 394802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String file, final Map<String, Object> paramMap) { 3957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye try { 3967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String xml; 3977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (file.endsWith(DOT_XML)) { 3987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Just read the file 3997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye xml = readTemplateTextResource(file); 40056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye if (xml == null) { 40156afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return; 40256afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye } 4037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 4047dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mLoader.setTemplateFile(new File(mRootPath, file)); 4057dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Template inputsTemplate = freemarker.getTemplate(file); 4067dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye StringWriter out = new StringWriter(); 4077dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye inputsTemplate.process(paramMap, out); 4087dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye out.flush(); 4097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye xml = out.toString(); 4107dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4117dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 4127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye SAXParserFactory factory = SAXParserFactory.newInstance(); 4137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye SAXParser saxParser = factory.newSAXParser(); 4147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye saxParser.parse(new ByteArrayInputStream(xml.getBytes()), new DefaultHandler() { 4157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Override 4167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void startElement(String uri, String localName, String name, 4177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Attributes attributes) 4187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye throws SAXException { 4197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (TAG_PARAMETER.equals(name)) { 4207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String id = attributes.getValue(ATTR_ID); 4217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (!paramMap.containsKey(id)) { 4227dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String value = attributes.getValue(ATTR_DEFAULT); 423c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye Object mapValue = value; 424c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye if (value != null && !value.isEmpty()) { 425c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye String type = attributes.getValue(ATTR_TYPE); 426c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye if ("boolean".equals(type)) { //$NON-NLS-1$ 427c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye mapValue = Boolean.valueOf(value); 428c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye } 429c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye } 430c689003930bebacf2aeffe48a361302c8b4697b5Tor Norbye paramMap.put(id, mapValue); 4317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (TAG_GLOBAL.equals(name)) { 4337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String id = attributes.getValue(ATTR_ID); 4347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (!paramMap.containsKey(id)) { 4357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String value = attributes.getValue(ATTR_VALUE); 4367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye paramMap.put(id, value); 4377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (TAG_GLOBALS.equals(name)) { 4397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Handle evaluation of variables 4407dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String path = attributes.getValue(ATTR_FILE); 4417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (path != null) { 442802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye processVariables(freemarker, path, paramMap); 4437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } // else: <globals> root element 4447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (TAG_EXECUTE.equals(name)) { 4457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String path = attributes.getValue(ATTR_FILE); 4467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (path != null) { 447802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye execute(freemarker, path, paramMap); 4487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 449dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye } else if (TAG_DEPENDENCY.equals(name)) { 450dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye String dependencyName = attributes.getValue(ATTR_NAME); 451dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye if (dependencyName.equals(SUPPORT_LIBRARY_NAME)) { 452dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye // We assume the revision requirement has been satisfied 453dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye // by the wizard 454b8397698e2834ed8af03c1bff7d570aff0e2f5bbRaphael Moll File path = AddSupportJarAction.getSupportJarFile(); 455dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye if (path != null) { 456802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IPath to = getTargetPath(FD_NATIVE_LIBS +'/' + path.getName()); 457dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye try { 458dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye copy(path, to); 459dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye } catch (IOException ioe) { 460dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye AdtPlugin.log(ioe, null); 461dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye } 462dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye } 463dd0a8b2ec052e0cc670cb8738b0f6ed7b292f122Tor Norbye } 4647dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (!name.equals("template") && !name.equals("category") 46556afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye && !name.equals("option") && !name.equals(TAG_THUMBS) && 466279445ad4561895db41309681de8dd1544d0ae22Tor Norbye !name.equals(TAG_THUMB) && !name.equals(TAG_ICONS)) { 4677dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye System.err.println("WARNING: Unknown template directive " + name); 4687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4697dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4707dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye }); 4717dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } catch (Exception e) { 4727dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye AdtPlugin.log(e, null); 4737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4747dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 4757dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 476b8397698e2834ed8af03c1bff7d570aff0e2f5bbRaphael Moll @SuppressWarnings("unused") 4777dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private boolean canOverwrite(File file) { 478802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (file.exists()) { 4797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Warn that the file already exists and ask the user what to do 4807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (!mYesToAll) { 4817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye MessageDialog dialog = new MessageDialog(null, "File Already Exists", null, 4827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String.format( 4837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye "%1$s already exists.\nWould you like to replace it?", 4847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye file.getPath()), 4857dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye MessageDialog.QUESTION, new String[] { 4867dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Yes will be moved to the end because it's the default 4877dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye "Yes", "No", "Cancel", "Yes to All" 4887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye }, 0); 4897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye int result = dialog.open(); 4907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye switch (result) { 4917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye case 0: 4927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Yes 4937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye break; 4947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye case 3: 4957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Yes to all 4967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mYesToAll = true; 4977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye break; 4987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye case 1: 4997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // No 5007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return false; 5017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye case SWT.DEFAULT: 5027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye case 2: 5037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Cancel 5047dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mNoToAll = true; 5057dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return false; 5067dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5077dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5087dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (mBackupMergedFiles) { 5107dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return makeBackup(file); 5117dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 5127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return file.delete(); 5137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return true; 5177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Executes the given recipe file: copying, merging, instantiating, opening files etc */ 5207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private void execute( 5217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye final Configuration freemarker, 5227dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String file, 523802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye final Map<String, Object> paramMap) { 5247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye try { 5257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mLoader.setTemplateFile(new File(mRootPath, file)); 5267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Template freemarkerTemplate = freemarker.getTemplate(file); 5277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye StringWriter out = new StringWriter(); 5297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye freemarkerTemplate.process(paramMap, out); 5307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye out.flush(); 5317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String xml = out.toString(); 5327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Parse and execute the resulting instruction list. 5347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye SAXParserFactory factory = SAXParserFactory.newInstance(); 5357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye SAXParser saxParser = factory.newSAXParser(); 5367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye saxParser.parse(new ByteArrayInputStream(xml.getBytes()), 5387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye new DefaultHandler() { 5397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Override 5407dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void startElement(String uri, String localName, String name, 5417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Attributes attributes) 5427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye throws SAXException { 5437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (mNoToAll) { 5447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return; 5457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5477dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye try { 5487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye boolean instantiate = TAG_INSTANTIATE.equals(name); 5497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (TAG_COPY.equals(name) || instantiate) { 5507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String fromPath = attributes.getValue(ATTR_FROM); 5517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String toPath = attributes.getValue(ATTR_TO); 5527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (toPath == null || toPath.isEmpty()) { 5537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye toPath = attributes.getValue(ATTR_FROM); 5547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye toPath = AdtUtils.stripSuffix(toPath, DOT_FTL); 5557dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 556802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IPath to = getTargetPath(toPath); 5577dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (instantiate) { 5587dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye instantiate(freemarker, paramMap, fromPath, to); 5597dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 560802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye copyTemplateResource(fromPath, to); 5617dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (TAG_MERGE.equals(name)) { 5637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String fromPath = attributes.getValue(ATTR_FROM); 5647dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String toPath = attributes.getValue(ATTR_TO); 5657dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (toPath == null || toPath.isEmpty()) { 5667dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye toPath = attributes.getValue(ATTR_FROM); 5677dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye toPath = AdtUtils.stripSuffix(toPath, DOT_FTL); 5687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5697dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Resources in template.xml are located within root/ 570802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IPath to = getTargetPath(toPath); 5717dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye merge(freemarker, paramMap, fromPath, to); 5727dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (name.equals(TAG_OPEN)) { 5737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // The relative path here is within the output directory: 5747dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String relativePath = attributes.getValue(ATTR_FILE); 5757dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (relativePath != null && !relativePath.isEmpty()) { 5767dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mOpen.add(relativePath); 5777dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5787dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else if (!name.equals("recipe")) { //$NON-NLS-1$ 5797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye System.err.println("WARNING: Unknown template directive " + name); 5807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } catch (Exception e) { 5827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye AdtPlugin.log(e, null); 5837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5857dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye }); 5867dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 5877dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } catch (Exception e) { 5887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye AdtPlugin.log(e, null); 5897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 59256afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye @NonNull 59356afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye private File getFullPath(@NonNull String fromPath) { 5947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (fromPath.startsWith(VALUE_TEMPLATE_DIR)) { 59556afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return new File(getTemplateRootFolder(), RESOURCE_ROOT + File.separator 59656afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye + fromPath.substring(VALUE_TEMPLATE_DIR.length() + 1).replace('/', 59756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye File.separatorChar)); 5987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 5997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return new File(mRootPath, DATA_ROOT + File.separator + fromPath); 6007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 602802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye @NonNull 603802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private IPath getTargetPath(@NonNull String relative) { 604802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (relative.indexOf('\\') != -1) { 605802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye relative = relative.replace('\\', '/'); 606802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 607802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye return new Path(relative); 608802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 609802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 610802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye @NonNull 611802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private IFile getTargetFile(@NonNull IPath path) { 612802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye return mProject.getFile(path); 613802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 614802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 6157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private void merge( 6167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull final Configuration freemarker, 6177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull final Map<String, Object> paramMap, 6187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull String relativeFrom, 619802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye @NonNull IPath toPath) throws IOException, TemplateException { 620802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 621802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String currentXml = null; 622802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 623802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IFile to = getTargetFile(toPath); 624802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (to.exists()) { 625802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye currentXml = AdtPlugin.readFile(to); 626802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 627802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 628802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (currentXml == null) { 6297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // The target file doesn't exist: don't merge, just copy 6307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye boolean instantiate = relativeFrom.endsWith(DOT_FTL); 6317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (instantiate) { 632802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye instantiate(freemarker, paramMap, relativeFrom, toPath); 6337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 634802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye copyTemplateResource(relativeFrom, toPath); 6357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return; 6377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 639802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (!to.getFileExtension().equals(EXT_XML)) { 6407dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye throw new RuntimeException("Only XML files can be merged at this point: " + to); 6417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 6437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String xml = null; 6447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye File from = getFullPath(relativeFrom); 6457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (relativeFrom.endsWith(DOT_FTL)) { 6467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Perform template substitution of the template prior to merging 6477dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mLoader.setTemplateFile(from); 6487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Template template = freemarker.getTemplate(from.getName()); 6497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Writer out = new StringWriter(); 6507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye template.process(paramMap, out); 6517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye out.flush(); 6527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye xml = out.toString(); 6537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 6547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye xml = readTemplateTextResource(from); 6557e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye if (xml == null) { 6567e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye return; 6577e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye } 6587dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6597dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 6607dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Document currentManifest = DomUtilities.parseStructuredDocument(currentXml); 6617dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Document fragment = DomUtilities.parseStructuredDocument(xml); 6627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 6637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye XmlFormatStyle formatStyle = XmlFormatStyle.MANIFEST; 6647dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye boolean modified; 6657dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye boolean ok; 666802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String fileName = to.getName(); 667802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (fileName.equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) { 6687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye modified = ok = mergeManifest(currentManifest, fragment); 6697dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 6707dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Merge plain XML files 671802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String parentFolderName = to.getParent().getName(); 672802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye ResourceFolderType folderType = ResourceFolderType.getFolderType(parentFolderName); 6737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (folderType != null) { 674802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye formatStyle = XmlFormatStyle.getForFile(toPath); 6757dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 6767dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye formatStyle = XmlFormatStyle.FILE; 6777dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6787dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 6797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye modified = mergeResourceFile(currentManifest, fragment, folderType, paramMap); 6807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye ok = true; 6817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 6837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Finally write out the merged file (formatting etc) 684802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String contents = null; 6857dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (ok) { 6867dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (modified) { 6877dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye XmlPrettyPrinter printer = new XmlPrettyPrinter( 6887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye XmlFormatPreferences.create(), formatStyle, null); 6897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye StringBuilder sb = new StringBuilder(2 ); 6907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye printer.prettyPrint(-1, currentManifest, null, null, sb, false /*openTagOnly*/); 691802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye contents = sb.toString(); 6927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 6937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 6947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Just insert into file along with comment, using the "standard" conflict 6957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // syntax that many tools and editors recognize. 6961fb460987f7d832adf12290f41448d0c16a95972Siva Velusamy String sep = SdkUtils.getLineSeparator(); 697802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye contents = 6987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye "<<<<<<< Original" + sep 6997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye + currentXml + sep 7007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye + "=======" + sep 7017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye + xml 7027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye + ">>>>>>> Added" + sep; 7037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7047dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 705802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (contents != null) { 706802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye TextFileChange change = new TextFileChange("Merge " + fileName, to); 707802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye MultiTextEdit rootEdit = new MultiTextEdit(); 708802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye rootEdit.addChild(new ReplaceEdit(0, currentXml.length(), contents)); 709802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye change.setEdit(rootEdit); 71012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye change.setTextType(SdkConstants.EXT_XML); 711802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mMergeChanges.add(change); 7127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Merges the given resource file contents into the given resource file 7167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * @param paramMap */ 7177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private boolean mergeResourceFile(Document currentManifest, Document fragment, 7187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye ResourceFolderType folderType, Map<String, Object> paramMap) { 7197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye boolean modified = false; 7207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // For layouts for example, I want to *append* inside the root all the 7227dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // contents of the new file. 7237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // But for resources for example, I want to combine elements which specify 7247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // the same name or id attribute. 7257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // For elements like manifest files we need to insert stuff at the right 7267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // location in a nested way (activities in the application element etc) 7277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // but that doesn't happen for the other file types. 7287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Element root = fragment.getDocumentElement(); 7297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye NodeList children = root.getChildNodes(); 7307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye List<Node> nodes = new ArrayList<Node>(children.getLength()); 7317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye for (int i = children.getLength() - 1; i >= 0; i--) { 7327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Node child = children.item(i); 7337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye nodes.add(child); 7347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye root.removeChild(child); 7357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye root = currentManifest.getDocumentElement(); 7387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (folderType == ResourceFolderType.VALUES) { 7407dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Try to merge items of the same name 7417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Map<String, Node> old = new HashMap<String, Node>(); 7427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye NodeList newSiblings = root.getChildNodes(); 7437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye for (int i = newSiblings.getLength() - 1; i >= 0; i--) { 7447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Node child = newSiblings.item(i); 7457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (child.getNodeType() == Node.ELEMENT_NODE) { 7467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Element element = (Element) child; 7477dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String name = getResourceId(element); 7487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (name != null) { 7497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye old.put(name, element); 7507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye for (Node node : nodes) { 7557dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (node.getNodeType() == Node.ELEMENT_NODE) { 7567dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Element element = (Element) node; 7577dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String name = getResourceId(element); 7587dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Node replace = name != null ? old.get(name) : null; 7597dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (replace != null) { 7607dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // There is an existing item with the same id: just replace it 7617dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // ACTUALLY -- let's NOT change it. 7627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Let's say you've used the activity wizard once, and it 7637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // emits some configuration parameter as a resource that 7647dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // it depends on, say "padding". Then the user goes and 7657dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // tweaks the padding to some other number. 7667dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // Now running the wizard a *second* time for some new activity, 7677dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // we should NOT go and set the value back to the template's 7687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // default! 7697dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye //root.replaceChild(node, replace); 7707dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7717dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // ... ON THE OTHER HAND... What if it's a parameter class 7727dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // (where the template rewrites a common attribute). Here it's 7737dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // really confusing if the new parameter is not set. This is 7747dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // really an error in the template, since we shouldn't have conflicts 7757dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // like that, but we need to do something to help track this down. 7767dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye AdtPlugin.log(null, 7777dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye "Warning: Ignoring name conflict in resource file for name %1$s", 7787dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye name); 7797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 7807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye root.appendChild(node); 7817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye modified = true; 7827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7857dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 7867dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // In other file types, such as layouts, just append all the new content 7877dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // at the end. 7887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye for (Node node : nodes) { 7897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye root.appendChild(node); 7907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye modified = true; 7917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return modified; 7947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 7957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 7967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Merges the given manifest fragment into the given manifest file */ 7977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private boolean mergeManifest(Document currentManifest, Document fragment) { 7981311018325c75993ae84183b41d3fd915bce965dRaphael Moll // TODO change MergerLog.wrapSdkLog by a custom IMergerLog that will create 7991311018325c75993ae84183b41d3fd915bce965dRaphael Moll // and maintain error markers. 8000386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Moll ManifestMerger merger = new ManifestMerger( 8010386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Moll MergerLog.wrapSdkLog(AdtPlugin.getDefault()), 8020386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Moll new AdtManifestMergeCallback()); 8030386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Moll return currentManifest != null && 8040386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Moll fragment != null && 8050386f5dcf9d0f472f243506be3c40f5cf46287a2Raphael Moll merger.process(currentManifest, fragment); 8067dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8077dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 8087dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 8097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Makes a backup of the given file, if it exists, by renaming it to name~ 8107dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * (and removing an old name~ file if it exists) 8117dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 8127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private static boolean makeBackup(File file) { 8137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (!file.exists()) { 8147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return true; 8157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (file.isDirectory()) { 8177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return false; 8187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 8207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye File backupFile = new File(file.getParentFile(), file.getName() + '~'); 8217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (backupFile.exists()) { 8227dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye backupFile.delete(); 8237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return file.renameTo(backupFile); 8257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 8277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private static String getResourceId(Element element) { 8287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String name = element.getAttribute(ATTR_NAME); 8297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (name == null) { 8307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye name = element.getAttribute(ATTR_ID); 8317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 8337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return name; 8347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 8357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 8367dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Instantiates the given template file into the given output file */ 8377dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private void instantiate( 8387dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull final Configuration freemarker, 8397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull final Map<String, Object> paramMap, 8407dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull String relativeFrom, 841802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye @NonNull IPath to) throws IOException, TemplateException { 8427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // For now, treat extension-less files as directories... this isn't quite right 8437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // so I should refine this! Maybe with a unique attribute in the template file? 8447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye boolean isDirectory = relativeFrom.indexOf('.') == -1; 8457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (isDirectory) { 8467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye // It's a directory 847802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye copyTemplateResource(relativeFrom, to); 8487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 8497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye File from = getFullPath(relativeFrom); 8507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mLoader.setTemplateFile(from); 8517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Template template = freemarker.getTemplate(from.getName()); 8527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Writer out = new StringWriter(1024); 8537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye template.process(paramMap, out); 8547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye out.flush(); 8557dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String contents = out.toString(); 8567dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 85757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye contents = format(mProject, contents, to); 858802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IFile targetFile = getTargetFile(to); 859802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye TextFileChange change = createTextChange(targetFile); 860802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye MultiTextEdit rootEdit = new MultiTextEdit(); 861802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye rootEdit.addChild(new InsertEdit(0, contents)); 862802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye change.setEdit(rootEdit); 863802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mTextChanges.add(change); 864802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 865802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 866802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 86757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye private static String format(IProject project, String contents, IPath to) { 86857d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye String name = to.lastSegment(); 86957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye if (name.endsWith(DOT_XML)) { 87057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye XmlFormatStyle formatStyle = XmlFormatStyle.getForFile(to); 87157d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye XmlFormatPreferences prefs = XmlFormatPreferences.create(); 87257d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye return XmlPrettyPrinter.prettyPrint(contents, prefs, formatStyle, null); 87357d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } else if (name.endsWith(DOT_JAVA)) { 87457d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye Map<?, ?> options = null; 87557d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye if (project != null && project.isAccessible()) { 87657d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye try { 87757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); 87857d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye if (javaProject != null) { 87957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye options = javaProject.getOptions(true); 88057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 88157d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } catch (CoreException e) { 88257d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye AdtPlugin.log(e, null); 88357d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 88457d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 88557d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye if (options == null) { 88657d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye options = JavaCore.getOptions(); 88757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 88857d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye 88957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye CodeFormatter formatter = ToolFactory.createCodeFormatter(options); 89057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye 89157d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye try { 89257d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye IDocument doc = new org.eclipse.jface.text.Document(); 89357d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye // format the file (the meat and potatoes) 89457d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye doc.set(contents); 89557d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye TextEdit edit = formatter.format( 89657d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, 89757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye contents, 0, contents.length(), 0, null); 89857d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye if (edit != null) { 89957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye edit.apply(doc); 90057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 90157d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye 90257d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye return doc.get(); 90357d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } catch (Exception e) { 90457d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye AdtPlugin.log(e, null); 90557d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 90657d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 90757d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye 90857d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye return contents; 90957d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye } 91057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye 911802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private static TextFileChange createTextChange(IFile targetFile) { 912802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String fileName = targetFile.getName(); 913802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String message; 914802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (targetFile.exists()) { 915802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye message = String.format("Replace %1$s", fileName); 916802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } else { 917802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye message = String.format("Create %1$s", fileName); 9187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 919802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 920802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye TextFileChange change = new TextFileChange(message, targetFile); 921802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye change.setTextType(fileName.substring(fileName.lastIndexOf('.') + 1)); 922802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye return change; 9237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 9257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 9267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Returns the list of files to open when the template has been created 9277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * 9287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * @return the list of files to open 9297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 9307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @NonNull 9317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public List<String> getFilesToOpen() { 9327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return mOpen; 9337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 935802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye /** Copy a template resource */ 936802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private final void copyTemplateResource( 93756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye @NonNull String relativeFrom, 938802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye @NonNull IPath output) throws IOException { 9397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye File from = getFullPath(relativeFrom); 94056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye copy(from, output); 9417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 9437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** Returns true if the given file contains the given bytes */ 944802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private static boolean isIdentical(@Nullable byte[] data, @NonNull IFile dest) { 945802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye assert dest.exists(); 946802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye byte[] existing = AdtUtils.readData(dest); 9477dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return Arrays.equals(existing, data); 9487dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9497dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 9507dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 9517dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * Copies the given source file into the given destination file (where the 9527dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * source is allowed to be a directory, in which case the whole directory is 9537dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * copied recursively) 9547dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 955802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye private void copy(File src, IPath path) throws IOException { 956802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (src.isDirectory()) { 9577dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye File[] children = src.listFiles(); 9587dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (children != null) { 9597dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye for (File child : children) { 960802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye copy(child, path.append(child.getName())); 9617dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9627dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9637dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } else { 964802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IResource dest = mProject.getFile(path); 965802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (dest.exists() && !(dest instanceof IFile)) {// Don't attempt to overwrite a folder 966802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye assert false : dest.getClass().getName(); 9677dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return; 9687dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 969802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IFile file = (IFile) dest; 970802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String targetName = path.lastSegment(); 971802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (dest instanceof IFile) { 972802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (dest.exists() && isIdentical(Files.toByteArray(src), file)) { 973802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String label = String.format( 974802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye "Not overwriting %1$s because the files are identical", targetName); 975802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye NullChange change = new NullChange(label); 976802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye change.setEnabled(false); 977802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mOtherChanges.add(change); 978802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye return; 979802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } 9807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 9817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 982802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye if (targetName.endsWith(DOT_XML) 983802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye || targetName.endsWith(DOT_JAVA) 984802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye || targetName.endsWith(DOT_TXT) 985802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye || targetName.endsWith(DOT_RS) 986802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye || targetName.endsWith(DOT_AIDL) 987802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye || targetName.endsWith(DOT_SVG)) { 988802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 989802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye String newFile = Files.toString(src, Charsets.UTF_8); 99057d3c8a0e1c17318f72af6f7e417d248c034f583Tor Norbye newFile = format(mProject, newFile, path); 991802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye 992802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye TextFileChange addFile = createTextChange(file); 993802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye addFile.setEdit(new InsertEdit(0, newFile)); 994802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mTextChanges.add(addFile); 995802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye } else { 996802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye // Write binary file: Need custom change for that 997802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye IPath workspacePath = mProject.getFullPath().append(path); 998802de810020fba3f86282cd1d66597a2a41698e3Tor Norbye mOtherChanges.add(new CreateFileChange(targetName, workspacePath, src)); 9997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye /** 10047dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * A custom {@link TemplateLoader} which locates and provides templates 10057dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye * within the plugin .jar file 10067dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye */ 10077dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private static final class MyTemplateLoader implements TemplateLoader { 10087dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye private String mPrefix; 10097dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10107dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void setPrefix(String prefix) { 10117dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mPrefix = prefix; 10127dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10137dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void setTemplateFile(File file) { 10157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye setTemplateParent(file.getParentFile()); 10167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10187dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void setTemplateParent(File parent) { 10197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mPrefix = parent.getPath(); 10207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10227dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Override 10237dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public Reader getReader(Object templateSource, String encoding) throws IOException { 10247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye URL url = (URL) templateSource; 10257dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return new InputStreamReader(url.openStream(), encoding); 10267dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10277dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10287dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Override 10297dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public long getLastModified(Object templateSource) { 10307dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return 0; 10317dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10327dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Override 10347dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public Object findTemplateSource(String name) throws IOException { 10357dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye String path = mPrefix != null ? mPrefix + '/' + name : name; 103656afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye File file = new File(path); 103756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye if (file.exists()) { 103856afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return file.toURI().toURL(); 10397dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 104056afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye return null; 10417dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10427dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 10437dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Override 10447dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void closeTemplateSource(Object templateSource) throws IOException { 10457dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 10467dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 104756afaff9c34a60c0e850324938d101a0509f8a38Tor Norbye 10487f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye /** 10497f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye * Validates this template to make sure it's supported 10506d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye * @param currentMinSdk the minimum SDK in the project, or -1 or 0 if unknown (e.g. codename) 1051c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye * @param buildApi the build API, or -1 or 0 if unknown (e.g. codename) 10527f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye * 10537f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye * @return a status object with the error, or null if there is no problem 10547f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye */ 10557f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye @SuppressWarnings("cast") // In Eclipse 3.6.2 cast below is needed 10567f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye @Nullable 1057c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye public IStatus validateTemplate(int currentMinSdk, int buildApi) { 10587f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye TemplateMetadata template = getTemplate(); 10596d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye if (template == null) { 10606d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye return null; 10616d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye } 10626d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye if (!template.isSupported()) { 10637f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye String versionString = (String) AdtPlugin.getDefault().getBundle().getHeaders().get( 10647f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye Constants.BUNDLE_VERSION); 10657f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye Version version = new Version(versionString); 10667f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 10677f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye String.format("This template requires a more recent version of the " + 10687f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye "Android Eclipse plugin. Please update from version %1$d.%2$d.%3$d.", 10697f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye version.getMajor(), version.getMinor(), version.getMicro())); 10707f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye } 10716d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye int templateMinSdk = template.getMinSdk(); 10726d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye if (templateMinSdk > currentMinSdk && currentMinSdk >= 1) { 10736d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 10746d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye String.format("This template requires a minimum SDK version of at " + 10756d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye "least %1$d, and the current min version is %2$d", 10766d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye templateMinSdk, currentMinSdk)); 10776d1e4fdd6b2132b895aae80de3dba83c3960d43fTor Norbye } 1078c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye int templateMinBuildApi = template.getMinBuildApi(); 1079c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye if (templateMinBuildApi > buildApi && buildApi >= 1) { 1080c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 1081c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye String.format("This template requires a build target API version of at " + 1082c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye "least %1$d, and the current version is %2$d", 1083c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye templateMinBuildApi, buildApi)); 1084c58247bd46d86afe244d2d9dd9160da10e0db648Tor Norbye } 10857f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye 10867f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye return null; 10877f10682cf646bcb3e761fbb6bcb2f645bd748c03Tor Norbye } 10887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye} 1089