1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.refactorings.core; 18 19 import static com.android.SdkConstants.ANDROID_URI; 20 import static com.android.SdkConstants.ATTR_NAME; 21 import static com.android.xml.AndroidManifest.ATTRIBUTE_BACKUP_AGENT; 22 import static com.android.xml.AndroidManifest.ATTRIBUTE_MANAGE_SPACE_ACTIVITY; 23 import static com.android.xml.AndroidManifest.ATTRIBUTE_PARENT_ACTIVITY_NAME; 24 import static com.android.xml.AndroidManifest.ATTRIBUTE_TARGET_ACTIVITY; 25 26 import com.android.annotations.NonNull; 27 import com.android.annotations.Nullable; 28 import com.android.ide.eclipse.adt.AdtPlugin; 29 import com.android.xml.AndroidManifest; 30 31 import org.eclipse.core.runtime.CoreException; 32 import org.eclipse.core.runtime.IStatus; 33 import org.eclipse.jface.text.BadLocationException; 34 import org.eclipse.jface.text.IDocument; 35 import org.eclipse.wst.sse.core.StructuredModelManager; 36 import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; 37 import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; 38 import org.w3c.dom.Attr; 39 import org.w3c.dom.Element; 40 41 import java.io.IOException; 42 import java.io.UnsupportedEncodingException; 43 44 /** 45 * The utility class for android refactoring 46 * 47 */ 48 @SuppressWarnings("restriction") 49 public class RefactoringUtil { 50 51 private static boolean sRefactorAppPackage = false; 52 53 /** 54 * Releases SSE read model; saves SSE model if exists edit model 55 * Called in dispose method of refactoring change classes 56 * 57 * @param model the SSE model 58 * @param document the document 59 */ 60 public static void fixModel(IStructuredModel model, IDocument document) { 61 if (model != null) { 62 model.releaseFromRead(); 63 } 64 model = null; 65 if (document == null) { 66 return; 67 } 68 try { 69 model = StructuredModelManager.getModelManager().getExistingModelForEdit(document); 70 if (model != null) { 71 model.save(); 72 } 73 } catch (UnsupportedEncodingException e1) { 74 // ignore 75 } catch (IOException e1) { 76 // ignore 77 } catch (CoreException e1) { 78 // ignore 79 } finally { 80 if (model != null) { 81 model.releaseFromEdit(); 82 } 83 } 84 } 85 86 /** 87 * Logs the info message 88 * 89 * @param message the message 90 */ 91 public static void logInfo(String message) { 92 AdtPlugin.log(IStatus.INFO, AdtPlugin.PLUGIN_ID, message); 93 } 94 95 /** 96 * Logs the the exception 97 * 98 * @param e the exception 99 */ 100 public static void log(Throwable e) { 101 AdtPlugin.log(e, e.getMessage()); 102 } 103 104 /** 105 * @return true if Rename/Move package needs to change the application package 106 * default is false 107 * 108 */ 109 public static boolean isRefactorAppPackage() { 110 return sRefactorAppPackage; 111 } 112 113 /** 114 * @param refactorAppPackage true if Rename/Move package needs to change the application package 115 */ 116 public static void setRefactorAppPackage(boolean refactorAppPackage) { 117 RefactoringUtil.sRefactorAppPackage = refactorAppPackage; 118 } 119 120 /** 121 * Returns the range of the attribute value in the given document 122 * 123 * @param attr the attribute to look up 124 * @param document the document containing the attribute 125 * @return the range of the value text, not including quotes, in the document 126 */ 127 public static int getAttributeValueRangeStart( 128 @NonNull Attr attr, 129 @NonNull IDocument document) { 130 IndexedRegion region = (IndexedRegion) attr; 131 int potentialStart = attr.getName().length() + 2; // + 2: add =" 132 String text; 133 try { 134 text = document.get(region.getStartOffset(), 135 region.getEndOffset() - region.getStartOffset()); 136 } catch (BadLocationException e) { 137 return -1; 138 } 139 String value = attr.getValue(); 140 int index = text.indexOf(value, potentialStart); 141 if (index != -1) { 142 return region.getStartOffset() + index; 143 } else { 144 return -1; 145 } 146 } 147 148 /** 149 * Returns the start of the tag name of the given element 150 * 151 * @param element the element to look up 152 * @param document the document containing the attribute 153 * @return the index of the start tag in the document 154 */ 155 public static int getTagNameRangeStart( 156 @NonNull Element element, 157 @NonNull IDocument document) { 158 IndexedRegion region = (IndexedRegion) element; 159 int potentialStart = 1; // add '<' 160 String text; 161 try { 162 text = document.get(region.getStartOffset(), 163 region.getEndOffset() - region.getStartOffset()); 164 } catch (BadLocationException e) { 165 return -1; 166 } 167 int index = text.indexOf(element.getTagName(), potentialStart); 168 if (index != -1) { 169 return region.getStartOffset() + index; 170 } else { 171 return -1; 172 } 173 } 174 175 /** 176 * Returns whether the given manifest attribute should be considered to describe 177 * a class name. These will be eligible for refactoring when classes are renamed 178 * or moved. 179 * 180 * @param attribute the manifest attribute 181 * @return true if this attribute can describe a class 182 */ 183 public static boolean isManifestClassAttribute(@NonNull Attr attribute) { 184 return isManifestClassAttribute( 185 attribute.getOwnerElement().getTagName(), 186 attribute.getNamespaceURI(), 187 attribute.getLocalName()); 188 } 189 190 /** 191 * Returns whether the given manifest attribute should be considered to describe 192 * a class name. These will be eligible for refactoring when classes are renamed 193 * or moved. 194 * 195 * @param tag the tag, if known 196 * @param uri the attribute namespace, if any 197 * @param name the attribute local name, if any 198 * @return true if this attribute can describe a class 199 */ 200 public static boolean isManifestClassAttribute( 201 @Nullable String tag, 202 @Nullable String uri, 203 @Nullable String name) { 204 if (name == null) { 205 return false; 206 } 207 208 if ((name.equals(ATTR_NAME) 209 && (AndroidManifest.NODE_ACTIVITY.equals(tag) 210 || AndroidManifest.NODE_APPLICATION.equals(tag) 211 || AndroidManifest.NODE_INSTRUMENTATION.equals(tag) 212 || AndroidManifest.NODE_PROVIDER.equals(tag) 213 || AndroidManifest.NODE_SERVICE.equals(tag) 214 || AndroidManifest.NODE_RECEIVER.equals(tag))) 215 || name.equals(ATTRIBUTE_TARGET_ACTIVITY) 216 || name.equals(ATTRIBUTE_MANAGE_SPACE_ACTIVITY) 217 || name.equals(ATTRIBUTE_BACKUP_AGENT) 218 || name.equals(ATTRIBUTE_PARENT_ACTIVITY_NAME)) { 219 return ANDROID_URI.equals(uri); 220 } 221 222 return false; 223 } 224 } 225