diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java | 1561 |
1 files changed, 0 insertions, 1561 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java deleted file mode 100644 index 93cd2da1e..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java +++ /dev/null @@ -1,1561 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.eclipse.org/org/documents/epl-v10.php - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.ide.eclipse.adt; - -import static com.android.SdkConstants.TOOLS_PREFIX; -import static com.android.SdkConstants.TOOLS_URI; -import static org.eclipse.ui.IWorkbenchPage.MATCH_INPUT; - -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.sdklib.SdkVersionInfo; -import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; -import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper.IProjectFilter; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.resources.ResourceFolderType; -import com.android.resources.ResourceType; -import com.android.sdklib.AndroidVersion; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.repository.PkgProps; -import com.android.utils.XmlUtils; -import com.google.common.io.ByteStreams; -import com.google.common.io.Closeables; - -import org.eclipse.core.filebuffers.FileBuffers; -import org.eclipse.core.filebuffers.ITextFileBuffer; -import org.eclipse.core.filebuffers.ITextFileBufferManager; -import org.eclipse.core.filebuffers.LocationKind; -import org.eclipse.core.filesystem.URIUtil; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.IURIEditorInput; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.editors.text.TextFileDocumentProvider; -import org.eclipse.ui.part.FileEditorInput; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.ui.texteditor.ITextEditor; -import org.eclipse.wst.sse.core.StructuredModelManager; -import org.eclipse.wst.sse.core.internal.provisional.IModelManager; -import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; -import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; -import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import java.io.File; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; - - -/** Utility methods for ADT */ -@SuppressWarnings("restriction") // WST API -public class AdtUtils { - /** - * Creates a Java class name out of the given string, if possible. For - * example, "My Project" becomes "MyProject", "hello" becomes "Hello", - * "Java's" becomes "Java", and so on. - * - * @param string the string to be massaged into a Java class - * @return the string as a Java class, or null if a class name could not be - * extracted - */ - @Nullable - public static String extractClassName(@NonNull String string) { - StringBuilder sb = new StringBuilder(string.length()); - int n = string.length(); - - int i = 0; - for (; i < n; i++) { - char c = Character.toUpperCase(string.charAt(i)); - if (Character.isJavaIdentifierStart(c)) { - sb.append(c); - i++; - break; - } - } - if (sb.length() > 0) { - for (; i < n; i++) { - char c = string.charAt(i); - if (Character.isJavaIdentifierPart(c)) { - sb.append(c); - } - } - - return sb.toString(); - } - - return null; - } - - /** - * Strips off the last file extension from the given filename, e.g. - * "foo.backup.diff" will be turned into "foo.backup". - * <p> - * Note that dot files (e.g. ".profile") will be left alone. - * - * @param filename the filename to be stripped - * @return the filename without the last file extension. - */ - public static String stripLastExtension(String filename) { - int dotIndex = filename.lastIndexOf('.'); - if (dotIndex > 0) { // > 0 instead of != -1: Treat dot files (e.g. .profile) differently - return filename.substring(0, dotIndex); - } else { - return filename; - } - } - - /** - * Strips off all extensions from the given filename, e.g. "foo.9.png" will - * be turned into "foo". - * <p> - * Note that dot files (e.g. ".profile") will be left alone. - * - * @param filename the filename to be stripped - * @return the filename without any file extensions - */ - public static String stripAllExtensions(String filename) { - int dotIndex = filename.indexOf('.'); - if (dotIndex > 0) { // > 0 instead of != -1: Treat dot files (e.g. .profile) differently - return filename.substring(0, dotIndex); - } else { - return filename; - } - } - - /** - * Strips the given suffix from the given string, provided that the string ends with - * the suffix. - * - * @param string the full string to strip from - * @param suffix the suffix to strip out - * @return the string without the suffix at the end - */ - public static String stripSuffix(@NonNull String string, @NonNull String suffix) { - if (string.endsWith(suffix)) { - return string.substring(0, string.length() - suffix.length()); - } - - return string; - } - - /** - * Capitalizes the string, i.e. transforms the initial [a-z] into [A-Z]. - * Returns the string unmodified if the first character is not [a-z]. - * - * @param str The string to capitalize. - * @return The capitalized string - */ - public static String capitalize(String str) { - if (str == null || str.length() < 1 || Character.isUpperCase(str.charAt(0))) { - return str; - } - - StringBuilder sb = new StringBuilder(); - sb.append(Character.toUpperCase(str.charAt(0))); - sb.append(str.substring(1)); - return sb.toString(); - } - - /** - * Converts a CamelCase word into an underlined_word - * - * @param string the CamelCase version of the word - * @return the underlined version of the word - */ - public static String camelCaseToUnderlines(String string) { - if (string.isEmpty()) { - return string; - } - - StringBuilder sb = new StringBuilder(2 * string.length()); - int n = string.length(); - boolean lastWasUpperCase = Character.isUpperCase(string.charAt(0)); - for (int i = 0; i < n; i++) { - char c = string.charAt(i); - boolean isUpperCase = Character.isUpperCase(c); - if (isUpperCase && !lastWasUpperCase) { - sb.append('_'); - } - lastWasUpperCase = isUpperCase; - c = Character.toLowerCase(c); - sb.append(c); - } - - return sb.toString(); - } - - /** - * Converts an underlined_word into a CamelCase word - * - * @param string the underlined word to convert - * @return the CamelCase version of the word - */ - public static String underlinesToCamelCase(String string) { - StringBuilder sb = new StringBuilder(string.length()); - int n = string.length(); - - int i = 0; - boolean upcaseNext = true; - for (; i < n; i++) { - char c = string.charAt(i); - if (c == '_') { - upcaseNext = true; - } else { - if (upcaseNext) { - c = Character.toUpperCase(c); - } - upcaseNext = false; - sb.append(c); - } - } - - return sb.toString(); - } - - /** - * Returns the current editor (the currently visible and active editor), or null if - * not found - * - * @return the current editor, or null - */ - public static IEditorPart getActiveEditor() { - IWorkbenchWindow window = getActiveWorkbenchWindow(); - if (window != null) { - IWorkbenchPage page = window.getActivePage(); - if (page != null) { - return page.getActiveEditor(); - } - } - - return null; - } - - /** - * Returns the current active workbench, or null if not found - * - * @return the current window, or null - */ - @Nullable - public static IWorkbenchWindow getActiveWorkbenchWindow() { - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - if (window == null) { - IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); - if (windows.length > 0) { - window = windows[0]; - } - } - - return window; - } - - /** - * Returns the current active workbench page, or null if not found - * - * @return the current page, or null - */ - @Nullable - public static IWorkbenchPage getActiveWorkbenchPage() { - IWorkbenchWindow window = getActiveWorkbenchWindow(); - if (window != null) { - IWorkbenchPage page = window.getActivePage(); - if (page == null) { - IWorkbenchPage[] pages = window.getPages(); - if (pages.length > 0) { - page = pages[0]; - } - } - - return page; - } - - return null; - } - - /** - * Returns the current active workbench part, or null if not found - * - * @return the current active workbench part, or null - */ - @Nullable - public static IWorkbenchPart getActivePart() { - IWorkbenchWindow window = getActiveWorkbenchWindow(); - if (window != null) { - IWorkbenchPage activePage = window.getActivePage(); - if (activePage != null) { - return activePage.getActivePart(); - } - } - return null; - } - - /** - * Returns the current text editor (the currently visible and active editor), or null - * if not found. - * - * @return the current text editor, or null - */ - public static ITextEditor getActiveTextEditor() { - IEditorPart editor = getActiveEditor(); - if (editor != null) { - if (editor instanceof ITextEditor) { - return (ITextEditor) editor; - } else { - return (ITextEditor) editor.getAdapter(ITextEditor.class); - } - } - - return null; - } - - /** - * Looks through the open editors and returns the editors that have the - * given file as input. - * - * @param file the file to search for - * @param restore whether editors should be restored (if they have an open - * tab, but the editor hasn't been restored since the most recent - * IDE start yet - * @return a collection of editors - */ - @NonNull - public static Collection<IEditorPart> findEditorsFor(@NonNull IFile file, boolean restore) { - FileEditorInput input = new FileEditorInput(file); - List<IEditorPart> result = null; - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); - for (IWorkbenchWindow window : windows) { - IWorkbenchPage[] pages = window.getPages(); - for (IWorkbenchPage page : pages) { - IEditorReference[] editors = page.findEditors(input, null, MATCH_INPUT); - if (editors != null) { - for (IEditorReference reference : editors) { - IEditorPart editor = reference.getEditor(restore); - if (editor != null) { - if (result == null) { - result = new ArrayList<IEditorPart>(); - } - result.add(editor); - } - } - } - } - } - - if (result == null) { - return Collections.emptyList(); - } - - return result; - } - - /** - * Attempts to convert the given {@link URL} into a {@link File}. - * - * @param url the {@link URL} to be converted - * @return the corresponding {@link File}, which may not exist - */ - @NonNull - public static File getFile(@NonNull URL url) { - try { - // First try URL.toURI(): this will work for URLs that contain %20 for spaces etc. - // Unfortunately, it *doesn't* work for "broken" URLs where the URL contains - // spaces, which is often the case. - return new File(url.toURI()); - } catch (URISyntaxException e) { - // ...so as a fallback, go to the old url.getPath() method, which handles space paths. - return new File(url.getPath()); - } - } - - /** - * Returns the file for the current editor, if any. - * - * @return the file for the current editor, or null if none - */ - public static IFile getActiveFile() { - IEditorPart editor = getActiveEditor(); - if (editor != null) { - IEditorInput input = editor.getEditorInput(); - if (input instanceof IFileEditorInput) { - IFileEditorInput fileInput = (IFileEditorInput) input; - return fileInput.getFile(); - } - } - - return null; - } - - /** - * Returns an absolute path to the given resource - * - * @param resource the resource to look up a path for - * @return an absolute file system path to the resource - */ - @NonNull - public static IPath getAbsolutePath(@NonNull IResource resource) { - IPath location = resource.getRawLocation(); - if (location != null) { - return location.makeAbsolute(); - } else { - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot root = workspace.getRoot(); - IPath workspacePath = root.getLocation(); - return workspacePath.append(resource.getFullPath()); - } - } - - /** - * Converts a workspace-relative path to an absolute file path - * - * @param path the workspace-relative path to convert - * @return the corresponding absolute file in the file system - */ - @NonNull - public static File workspacePathToFile(@NonNull IPath path) { - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IResource res = root.findMember(path); - if (res != null) { - IPath location = res.getLocation(); - if (location != null) { - return location.toFile(); - } - return root.getLocation().append(path).toFile(); - } - - return path.toFile(); - } - - /** - * Converts a {@link File} to an {@link IFile}, if possible. - * - * @param file a file to be converted - * @return the corresponding {@link IFile}, or null - */ - public static IFile fileToIFile(File file) { - if (!file.isAbsolute()) { - file = file.getAbsoluteFile(); - } - - IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot(); - IFile[] files = workspace.findFilesForLocationURI(file.toURI()); - if (files.length > 0) { - return files[0]; - } - - IPath filePath = new Path(file.getPath()); - return pathToIFile(filePath); - } - - /** - * Converts a {@link File} to an {@link IResource}, if possible. - * - * @param file a file to be converted - * @return the corresponding {@link IResource}, or null - */ - public static IResource fileToResource(File file) { - if (!file.isAbsolute()) { - file = file.getAbsoluteFile(); - } - - IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot(); - IFile[] files = workspace.findFilesForLocationURI(file.toURI()); - if (files.length > 0) { - return files[0]; - } - - IPath filePath = new Path(file.getPath()); - return pathToResource(filePath); - } - - /** - * Converts a {@link IPath} to an {@link IFile}, if possible. - * - * @param path a path to be converted - * @return the corresponding {@link IFile}, or null - */ - public static IFile pathToIFile(IPath path) { - IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot(); - - IFile[] files = workspace.findFilesForLocationURI(URIUtil.toURI(path.makeAbsolute())); - if (files.length > 0) { - return files[0]; - } - - IPath workspacePath = workspace.getLocation(); - if (workspacePath.isPrefixOf(path)) { - IPath relativePath = path.makeRelativeTo(workspacePath); - IResource member = workspace.findMember(relativePath); - if (member instanceof IFile) { - return (IFile) member; - } - } else if (path.isAbsolute()) { - return workspace.getFileForLocation(path); - } - - return null; - } - - /** - * Converts a {@link IPath} to an {@link IResource}, if possible. - * - * @param path a path to be converted - * @return the corresponding {@link IResource}, or null - */ - public static IResource pathToResource(IPath path) { - IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot(); - - IFile[] files = workspace.findFilesForLocationURI(URIUtil.toURI(path.makeAbsolute())); - if (files.length > 0) { - return files[0]; - } - - IPath workspacePath = workspace.getLocation(); - if (workspacePath.isPrefixOf(path)) { - IPath relativePath = path.makeRelativeTo(workspacePath); - return workspace.findMember(relativePath); - } else if (path.isAbsolute()) { - return workspace.getFileForLocation(path); - } - - return null; - } - - /** - * Returns all markers in a file/document that fit on the same line as the given offset - * - * @param markerType the marker type - * @param file the file containing the markers - * @param document the document showing the markers - * @param offset the offset to be checked - * @return a list (possibly empty but never null) of matching markers - */ - @NonNull - public static List<IMarker> findMarkersOnLine( - @NonNull String markerType, - @NonNull IResource file, - @NonNull IDocument document, - int offset) { - List<IMarker> matchingMarkers = new ArrayList<IMarker>(2); - try { - IMarker[] markers = file.findMarkers(markerType, true, IResource.DEPTH_ZERO); - - // Look for a match on the same line as the caret. - IRegion lineInfo = document.getLineInformationOfOffset(offset); - int lineStart = lineInfo.getOffset(); - int lineEnd = lineStart + lineInfo.getLength(); - int offsetLine = document.getLineOfOffset(offset); - - - for (IMarker marker : markers) { - int start = marker.getAttribute(IMarker.CHAR_START, -1); - int end = marker.getAttribute(IMarker.CHAR_END, -1); - if (start >= lineStart && start <= lineEnd && end > start) { - matchingMarkers.add(marker); - } else if (start == -1 && end == -1) { - // Some markers don't set character range, they only set the line - int line = marker.getAttribute(IMarker.LINE_NUMBER, -1); - if (line == offsetLine + 1) { - matchingMarkers.add(marker); - } - } - } - } catch (CoreException e) { - AdtPlugin.log(e, null); - } catch (BadLocationException e) { - AdtPlugin.log(e, null); - } - - return matchingMarkers; - } - - /** - * Returns the available and open Android projects - * - * @return the available and open Android projects, never null - */ - @NonNull - public static IJavaProject[] getOpenAndroidProjects() { - return BaseProjectHelper.getAndroidProjects(new IProjectFilter() { - @Override - public boolean accept(IProject project) { - return project.isAccessible(); - } - }); - } - - /** - * Returns a unique project name, based on the given {@code base} file name - * possibly with a {@code conjunction} and a new number behind it to ensure - * that the project name is unique. For example, - * {@code getUniqueProjectName("project", "_")} will return - * {@code "project"} if that name does not already exist, and if it does, it - * will return {@code "project_2"}. - * - * @param base the base name to use, such as "foo" - * @param conjunction a string to insert between the base name and the - * number. - * @return a unique project name based on the given base and conjunction - */ - public static String getUniqueProjectName(String base, String conjunction) { - // We're using all workspace projects here rather than just open Android project - // via getOpenAndroidProjects because the name cannot conflict with non-Android - // or closed projects either - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IProject[] projects = workspaceRoot.getProjects(); - - for (int i = 1; i < 1000; i++) { - String name = i == 1 ? base : base + conjunction + Integer.toString(i); - boolean found = false; - for (IProject project : projects) { - // Need to make case insensitive comparison, since otherwise we can hit - // org.eclipse.core.internal.resources.ResourceException: - // A resource exists with a different case: '/test'. - if (project.getName().equalsIgnoreCase(name)) { - found = true; - break; - } - } - if (!found) { - return name; - } - } - - return base; - } - - /** - * Returns the name of the parent folder for the given editor input - * - * @param editorInput the editor input to check - * @return the parent folder, which is never null but may be "" - */ - @NonNull - public static String getParentFolderName(@Nullable IEditorInput editorInput) { - if (editorInput instanceof IFileEditorInput) { - IFile file = ((IFileEditorInput) editorInput).getFile(); - return file.getParent().getName(); - } - - if (editorInput instanceof IURIEditorInput) { - IURIEditorInput urlEditorInput = (IURIEditorInput) editorInput; - String path = urlEditorInput.getURI().toString(); - int lastIndex = path.lastIndexOf('/'); - if (lastIndex != -1) { - int lastLastIndex = path.lastIndexOf('/', lastIndex - 1); - if (lastLastIndex != -1) { - return path.substring(lastLastIndex + 1, lastIndex); - } - } - } - - return ""; - } - - /** - * Returns the XML editor for the given editor part - * - * @param part the editor part to look up the editor for - * @return the editor or null if this part is not an XML editor - */ - @Nullable - public static AndroidXmlEditor getXmlEditor(@NonNull IEditorPart part) { - if (part instanceof AndroidXmlEditor) { - return (AndroidXmlEditor) part; - } else if (part instanceof GraphicalEditorPart) { - ((GraphicalEditorPart) part).getEditorDelegate().getEditor(); - } - - return null; - } - - /** - * Sets the given tools: attribute in the given XML editor document, adding - * the tools name space declaration if necessary, formatting the affected - * document region, and optionally comma-appending to an existing value and - * optionally opening and revealing the attribute. - * - * @param editor the associated editor - * @param element the associated element - * @param description the description of the attribute (shown in the undo - * event) - * @param name the name of the attribute - * @param value the attribute value - * @param reveal if true, open the editor and select the given attribute - * node - * @param appendValue if true, add this value as a comma separated value to - * the existing attribute value, if any - */ - public static void setToolsAttribute( - @NonNull final AndroidXmlEditor editor, - @NonNull final Element element, - @NonNull final String description, - @NonNull final String name, - @Nullable final String value, - final boolean reveal, - final boolean appendValue) { - editor.wrapUndoEditXmlModel(description, new Runnable() { - @Override - public void run() { - String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, null, true); - if (prefix == null) { - // Add in new prefix... - prefix = XmlUtils.lookupNamespacePrefix(element, - TOOLS_URI, TOOLS_PREFIX, true /*create*/); - if (value != null) { - // ...and ensure that the header is formatted such that - // the XML namespace declaration is placed in the right - // position and wrapping is applied etc. - editor.scheduleNodeReformat(editor.getUiRootNode(), - true /*attributesOnly*/); - } - } - - String v = value; - if (appendValue && v != null) { - String prev = element.getAttributeNS(TOOLS_URI, name); - if (prev.length() > 0) { - v = prev + ',' + value; - } - } - - // Use the non-namespace form of set attribute since we can't - // reference the namespace until the model has been reloaded - if (v != null) { - element.setAttribute(prefix + ':' + name, v); - } else { - element.removeAttribute(prefix + ':' + name); - } - - UiElementNode rootUiNode = editor.getUiRootNode(); - if (rootUiNode != null && v != null) { - final UiElementNode uiNode = rootUiNode.findXmlNode(element); - if (uiNode != null) { - editor.scheduleNodeReformat(uiNode, true /*attributesOnly*/); - - if (reveal) { - // Update editor selection after format - Display display = AdtPlugin.getDisplay(); - if (display != null) { - display.asyncExec(new Runnable() { - @Override - public void run() { - Node xmlNode = uiNode.getXmlNode(); - Attr attribute = ((Element) xmlNode).getAttributeNodeNS( - TOOLS_URI, name); - if (attribute instanceof IndexedRegion) { - IndexedRegion region = (IndexedRegion) attribute; - editor.getStructuredTextEditor().selectAndReveal( - region.getStartOffset(), region.getLength()); - } - } - }); - } - } - } - } - } - }); - } - - /** - * Returns a string label for the given target, of the form - * "API 16: Android 4.1 (Jelly Bean)". - * - * @param target the target to generate a string from - * @return a suitable display string - */ - @NonNull - public static String getTargetLabel(@NonNull IAndroidTarget target) { - if (target.isPlatform()) { - AndroidVersion version = target.getVersion(); - String codename = target.getProperty(PkgProps.PLATFORM_CODENAME); - String release = target.getProperty("ro.build.version.release"); //$NON-NLS-1$ - if (codename != null) { - return String.format("API %1$d: Android %2$s (%3$s)", - version.getApiLevel(), - release, - codename); - } - return String.format("API %1$d: Android %2$s", version.getApiLevel(), - release); - } - - return String.format("%1$s (API %2$s)", target.getFullName(), - target.getVersion().getApiString()); - } - - /** - * Sets the given tools: attribute in the given XML editor document, adding - * the tools name space declaration if necessary, and optionally - * comma-appending to an existing value. - * - * @param file the file associated with the element - * @param element the associated element - * @param description the description of the attribute (shown in the undo - * event) - * @param name the name of the attribute - * @param value the attribute value - * @param appendValue if true, add this value as a comma separated value to - * the existing attribute value, if any - */ - public static void setToolsAttribute( - @NonNull final IFile file, - @NonNull final Element element, - @NonNull final String description, - @NonNull final String name, - @Nullable final String value, - final boolean appendValue) { - IModelManager modelManager = StructuredModelManager.getModelManager(); - if (modelManager == null) { - return; - } - - try { - IStructuredModel model = null; - if (model == null) { - model = modelManager.getModelForEdit(file); - } - if (model != null) { - try { - model.aboutToChangeModel(); - if (model instanceof IDOMModel) { - IDOMModel domModel = (IDOMModel) model; - Document doc = domModel.getDocument(); - if (doc != null && element.getOwnerDocument() == doc) { - String prefix = XmlUtils.lookupNamespacePrefix(element, TOOLS_URI, - null, true); - if (prefix == null) { - // Add in new prefix... - prefix = XmlUtils.lookupNamespacePrefix(element, - TOOLS_URI, TOOLS_PREFIX, true); - } - - String v = value; - if (appendValue && v != null) { - String prev = element.getAttributeNS(TOOLS_URI, name); - if (prev.length() > 0) { - v = prev + ',' + value; - } - } - - // Use the non-namespace form of set attribute since we can't - // reference the namespace until the model has been reloaded - if (v != null) { - element.setAttribute(prefix + ':' + name, v); - } else { - element.removeAttribute(prefix + ':' + name); - } - } - } - } finally { - model.changedModel(); - String updated = model.getStructuredDocument().get(); - model.releaseFromEdit(); - model.save(file); - - // Must also force a save on disk since the above model.save(file) often - // (always?) has no effect. - ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager(); - NullProgressMonitor monitor = new NullProgressMonitor(); - IPath path = file.getFullPath(); - manager.connect(path, LocationKind.IFILE, monitor); - try { - ITextFileBuffer buffer = manager.getTextFileBuffer(path, - LocationKind.IFILE); - IDocument currentDocument = buffer.getDocument(); - currentDocument.set(updated); - buffer.commit(monitor, true); - } finally { - manager.disconnect(path, LocationKind.IFILE, monitor); - } - } - } - } catch (Exception e) { - AdtPlugin.log(e, null); - } - } - - /** - * Returns the Android version and code name of the given API level - * - * @param api the api level - * @return a suitable version display name - */ - public static String getAndroidName(int api) { - if (api <= SdkVersionInfo.HIGHEST_KNOWN_API) { - return SdkVersionInfo.getAndroidName(api); - } - - // Consult SDK manager to see if we know any more (later) names, - // installed by user - Sdk sdk = Sdk.getCurrent(); - if (sdk != null) { - for (IAndroidTarget target : sdk.getTargets()) { - if (target.isPlatform()) { - AndroidVersion version = target.getVersion(); - if (version.getApiLevel() == api) { - return getTargetLabel(target); - } - } - } - } - - return "API " + api; - } - - /** - * Returns the highest known API level to this version of ADT. The - * {@link #getAndroidName(int)} method will return real names up to and - * including this number. - * - * @return the highest known API number - */ - public static int getHighestKnownApiLevel() { - return SdkVersionInfo.HIGHEST_KNOWN_API; - } - - /** - * Returns a list of known API names - * - * @return a list of string API names, starting from 1 and up through the - * maximum known versions (with no gaps) - */ - public static String[] getKnownVersions() { - int max = getHighestKnownApiLevel(); - Sdk sdk = Sdk.getCurrent(); - if (sdk != null) { - for (IAndroidTarget target : sdk.getTargets()) { - if (target.isPlatform()) { - AndroidVersion version = target.getVersion(); - if (!version.isPreview()) { - max = Math.max(max, version.getApiLevel()); - } - } - } - } - - String[] versions = new String[max]; - for (int api = 1; api <= max; api++) { - versions[api-1] = getAndroidName(api); - } - - return versions; - } - - /** - * Returns the Android project(s) that are selected or active, if any. This - * considers the selection, the active editor, etc. - * - * @param selection the current selection - * @return a list of projects, possibly empty (but never null) - */ - @NonNull - public static List<IProject> getSelectedProjects(@Nullable ISelection selection) { - List<IProject> projects = new ArrayList<IProject>(); - - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection) selection; - // get the unique selected item. - Iterator<?> iterator = structuredSelection.iterator(); - while (iterator.hasNext()) { - Object element = iterator.next(); - - // First look up the resource (since some adaptables - // provide an IResource but not an IProject, and we can - // always go from IResource to IProject) - IResource resource = null; - if (element instanceof IResource) { // may include IProject - resource = (IResource) element; - } else if (element instanceof IAdaptable) { - IAdaptable adaptable = (IAdaptable)element; - Object adapter = adaptable.getAdapter(IResource.class); - resource = (IResource) adapter; - } - - // get the project object from it. - IProject project = null; - if (resource != null) { - project = resource.getProject(); - } else if (element instanceof IAdaptable) { - project = (IProject) ((IAdaptable) element).getAdapter(IProject.class); - } - - if (project != null && !projects.contains(project)) { - projects.add(project); - } - } - } - - if (projects.isEmpty()) { - // Try to look at the active editor instead - IFile file = AdtUtils.getActiveFile(); - if (file != null) { - projects.add(file.getProject()); - } - } - - if (projects.isEmpty()) { - // If we didn't find a default project based on the selection, check how many - // open Android projects we can find in the current workspace. If there's only - // one, we'll just select it by default. - IJavaProject[] open = AdtUtils.getOpenAndroidProjects(); - for (IJavaProject project : open) { - projects.add(project.getProject()); - } - return projects; - } else { - // Make sure all the projects are Android projects - List<IProject> androidProjects = new ArrayList<IProject>(projects.size()); - for (IProject project : projects) { - if (BaseProjectHelper.isAndroidProject(project)) { - androidProjects.add(project); - } - } - return androidProjects; - } - } - - private static Boolean sEclipse4; - - /** - * Returns true if the running Eclipse is version 4.x or later - * - * @return true if the current Eclipse version is 4.x or later, false - * otherwise - */ - public static boolean isEclipse4() { - if (sEclipse4 == null) { - sEclipse4 = Platform.getBundle("org.eclipse.e4.ui.model.workbench") != null; //$NON-NLS-1$ - } - - return sEclipse4; - } - - /** - * Reads the contents of an {@link IFile} and return it as a byte array - * - * @param file the file to be read - * @return the String read from the file, or null if there was an error - */ - @SuppressWarnings("resource") // Eclipse doesn't understand Closeables.closeQuietly yet - @Nullable - public static byte[] readData(@NonNull IFile file) { - InputStream contents = null; - try { - contents = file.getContents(); - return ByteStreams.toByteArray(contents); - } catch (Exception e) { - // Pass -- just return null - } finally { - Closeables.closeQuietly(contents); - } - - return null; - } - - /** - * Ensure that a given folder (and all its parents) are created. This implements - * the equivalent of {@link File#mkdirs()} for {@link IContainer} folders. - * - * @param container the container to ensure exists - * @throws CoreException if an error occurs - */ - public static void ensureExists(@Nullable IContainer container) throws CoreException { - if (container == null || container.exists()) { - return; - } - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IFolder folder = root.getFolder(container.getFullPath()); - ensureExists(folder); - } - - private static void ensureExists(IFolder folder) throws CoreException { - if (folder != null && !folder.exists()) { - IContainer parent = folder.getParent(); - if (parent instanceof IFolder) { - ensureExists((IFolder) parent); - } - folder.create(false, false, null); - } - } - - /** - * Format the given floating value into an XML string, omitting decimals if - * 0 - * - * @param value the value to be formatted - * @return the corresponding XML string for the value - */ - public static String formatFloatAttribute(float value) { - if (value != (int) value) { - // Run String.format without a locale, because we don't want locale-specific - // conversions here like separating the decimal part with a comma instead of a dot! - return String.format((Locale) null, "%.2f", value); //$NON-NLS-1$ - } else { - return Integer.toString((int) value); - } - } - - /** - * Creates all the directories required for the given path. - * - * @param wsPath the path to create all the parent directories for - * @return true if all the parent directories were created - */ - public static boolean createWsParentDirectory(IContainer wsPath) { - if (wsPath.getType() == IResource.FOLDER) { - if (wsPath.exists()) { - return true; - } - - IFolder folder = (IFolder) wsPath; - try { - if (createWsParentDirectory(wsPath.getParent())) { - folder.create(true /* force */, true /* local */, null /* monitor */); - return true; - } - } catch (CoreException e) { - e.printStackTrace(); - } - } - - return false; - } - - /** - * Lists the files of the given directory and returns them as an array which - * is never null. This simplifies processing file listings from for each - * loops since {@link File#listFiles} can return null. This method simply - * wraps it and makes sure it returns an empty array instead if necessary. - * - * @param dir the directory to list - * @return the children, or empty if it has no children, is not a directory, - * etc. - */ - @NonNull - public static File[] listFiles(File dir) { - File[] files = dir.listFiles(); - if (files != null) { - return files; - } else { - return new File[0]; - } - } - - /** - * Closes all open editors that are showing a file for the given project. This method - * should be called when a project is closed or deleted. - * <p> - * This method can be called from any thread, but if it is not called on the GUI thread - * the editor will be closed asynchronously. - * - * @param project the project to close all editors for - * @param save whether unsaved editors should be saved first - */ - public static void closeEditors(@NonNull final IProject project, final boolean save) { - final Display display = AdtPlugin.getDisplay(); - if (display == null || display.isDisposed()) { - return; - } - if (display.getThread() != Thread.currentThread()) { - display.asyncExec(new Runnable() { - @Override - public void run() { - closeEditors(project, save); - } - }); - return; - } - - // Close editors for removed files - IWorkbench workbench = PlatformUI.getWorkbench(); - for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) { - for (IWorkbenchPage page : window.getPages()) { - List<IEditorReference> matching = null; - for (IEditorReference ref : page.getEditorReferences()) { - boolean close = false; - try { - IEditorInput input = ref.getEditorInput(); - if (input instanceof IFileEditorInput) { - IFileEditorInput fileInput = (IFileEditorInput) input; - if (project.equals(fileInput.getFile().getProject())) { - close = true; - } - } - } catch (PartInitException ex) { - close = true; - } - if (close) { - if (matching == null) { - matching = new ArrayList<IEditorReference>(2); - } - matching.add(ref); - } - } - if (matching != null) { - IEditorReference[] refs = new IEditorReference[matching.size()]; - page.closeEditors(matching.toArray(refs), save); - } - } - } - } - - /** - * Closes all open editors for the given file. Note that a file can be open in - * more than one editor, for example by using Open With on the file to choose different - * editors. - * <p> - * This method can be called from any thread, but if it is not called on the GUI thread - * the editor will be closed asynchronously. - * - * @param file the file whose editors should be closed. - * @param save whether unsaved editors should be saved first - */ - public static void closeEditors(@NonNull final IFile file, final boolean save) { - final Display display = AdtPlugin.getDisplay(); - if (display == null || display.isDisposed()) { - return; - } - if (display.getThread() != Thread.currentThread()) { - display.asyncExec(new Runnable() { - @Override - public void run() { - closeEditors(file, save); - } - }); - return; - } - - // Close editors for removed files - IWorkbench workbench = PlatformUI.getWorkbench(); - for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) { - for (IWorkbenchPage page : window.getPages()) { - List<IEditorReference> matching = null; - for (IEditorReference ref : page.getEditorReferences()) { - boolean close = false; - try { - IEditorInput input = ref.getEditorInput(); - if (input instanceof IFileEditorInput) { - IFileEditorInput fileInput = (IFileEditorInput) input; - if (file.equals(fileInput.getFile())) { - close = true; - } - } - } catch (PartInitException ex) { - close = true; - } - if (close) { - // Found - if (matching == null) { - matching = new ArrayList<IEditorReference>(2); - } - matching.add(ref); - // We don't break here in case the file is - // opened multiple times with different editors. - } - } - if (matching != null) { - IEditorReference[] refs = new IEditorReference[matching.size()]; - page.closeEditors(matching.toArray(refs), save); - } - } - } - } - - /** - * Returns the offset region of the given 0-based line number in the given - * file - * - * @param file the file to look up the line number in - * @param line the line number (0-based, meaning that the first line is line - * 0) - * @return the corresponding offset range, or null - */ - @Nullable - public static IRegion getRegionOfLine(@NonNull IFile file, int line) { - IDocumentProvider provider = new TextFileDocumentProvider(); - try { - provider.connect(file); - IDocument document = provider.getDocument(file); - if (document != null) { - return document.getLineInformation(line); - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't find range information for %1$s", file.getName()); - } finally { - provider.disconnect(file); - } - - return null; - } - - /** - * Returns all resource variations for the given file - * - * @param file resource file, which should be an XML file in one of the - * various resource folders, e.g. res/layout, res/values-xlarge, etc. - * @param includeSelf if true, include the file itself in the list, - * otherwise exclude it - * @return a list of all the resource variations - */ - public static List<IFile> getResourceVariations(@Nullable IFile file, boolean includeSelf) { - if (file == null) { - return Collections.emptyList(); - } - - // Compute the set of layout files defining this layout resource - List<IFile> variations = new ArrayList<IFile>(); - String name = file.getName(); - IContainer parent = file.getParent(); - if (parent != null) { - IContainer resFolder = parent.getParent(); - if (resFolder != null) { - String parentName = parent.getName(); - String prefix = parentName; - int qualifiers = prefix.indexOf('-'); - - if (qualifiers != -1) { - parentName = prefix.substring(0, qualifiers); - prefix = prefix.substring(0, qualifiers + 1); - } else { - prefix = prefix + '-'; - } - try { - for (IResource resource : resFolder.members()) { - String n = resource.getName(); - if ((n.startsWith(prefix) || n.equals(parentName)) - && resource instanceof IContainer) { - IContainer layoutFolder = (IContainer) resource; - IResource r = layoutFolder.findMember(name); - if (r instanceof IFile) { - IFile variation = (IFile) r; - if (!includeSelf && file.equals(variation)) { - continue; - } - variations.add(variation); - } - } - } - } catch (CoreException e) { - AdtPlugin.log(e, null); - } - } - } - - return variations; - } - - /** - * Returns whether the current thread is the UI thread - * - * @return true if the current thread is the UI thread - */ - public static boolean isUiThread() { - return AdtPlugin.getDisplay() != null - && AdtPlugin.getDisplay().getThread() == Thread.currentThread(); - } - - /** - * Replaces any {@code \\uNNNN} references in the given string with the corresponding - * unicode characters. - * - * @param s the string to perform replacements in - * @return the string with unicode escapes replaced with actual characters - */ - @NonNull - public static String replaceUnicodeEscapes(@NonNull String s) { - // Handle unicode escapes - if (s.indexOf("\\u") != -1) { //$NON-NLS-1$ - StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0, n = s.length(); i < n; i++) { - char c = s.charAt(i); - if (c == '\\' && i < n - 1) { - char next = s.charAt(i + 1); - if (next == 'u' && i < n - 5) { // case sensitive - String hex = s.substring(i + 2, i + 6); - try { - int unicodeValue = Integer.parseInt(hex, 16); - sb.append((char) unicodeValue); - i += 5; - continue; - } catch (NumberFormatException nufe) { - // Invalid escape: Just proceed to literally transcribe it - sb.append(c); - } - } else { - sb.append(c); - sb.append(next); - i++; - continue; - } - } else { - sb.append(c); - } - } - s = sb.toString(); - } - - return s; - } - - /** - * Looks up the {@link ResourceFolderType} corresponding to a given - * {@link ResourceType}: the folder where those resources can be found. - * <p> - * Note that {@link ResourceType#ID} is a special case: it can not just - * be defined in {@link ResourceFolderType#VALUES}, but it can also be - * defined inline via {@code @+id} in {@link ResourceFolderType#LAYOUT} and - * {@link ResourceFolderType#MENU} folders. - * - * @param type the resource type - * @return the corresponding resource folder type - */ - @NonNull - public static ResourceFolderType getFolderTypeFor(@NonNull ResourceType type) { - switch (type) { - case ANIM: - return ResourceFolderType.ANIM; - case ANIMATOR: - return ResourceFolderType.ANIMATOR; - case ARRAY: - return ResourceFolderType.VALUES; - case COLOR: - return ResourceFolderType.COLOR; - case DRAWABLE: - return ResourceFolderType.DRAWABLE; - case INTERPOLATOR: - return ResourceFolderType.INTERPOLATOR; - case LAYOUT: - return ResourceFolderType.LAYOUT; - case MENU: - return ResourceFolderType.MENU; - case MIPMAP: - return ResourceFolderType.MIPMAP; - case RAW: - return ResourceFolderType.RAW; - case XML: - return ResourceFolderType.XML; - case ATTR: - case BOOL: - case DECLARE_STYLEABLE: - case DIMEN: - case FRACTION: - case ID: - case INTEGER: - case PLURALS: - case PUBLIC: - case STRING: - case STYLE: - case STYLEABLE: - return ResourceFolderType.VALUES; - default: - assert false : type; - return ResourceFolderType.VALUES; - - } - } - - /** - * Looks up the {@link ResourceType} defined in a given {@link ResourceFolderType}. - * <p> - * Note that for {@link ResourceFolderType#VALUES} there are many, many - * different types of resources that can be defined, so this method returns - * {@code null} for that scenario. - * <p> - * Note also that {@link ResourceType#ID} is a special case: it can not just - * be defined in {@link ResourceFolderType#VALUES}, but it can also be - * defined inline via {@code @+id} in {@link ResourceFolderType#LAYOUT} and - * {@link ResourceFolderType#MENU} folders. - * - * @param folderType the resource folder type - * @return the corresponding resource type, or null if {@code folderType} is - * {@link ResourceFolderType#VALUES} - */ - @Nullable - public static ResourceType getResourceTypeFor(@NonNull ResourceFolderType folderType) { - switch (folderType) { - case ANIM: - return ResourceType.ANIM; - case ANIMATOR: - return ResourceType.ANIMATOR; - case COLOR: - return ResourceType.COLOR; - case DRAWABLE: - return ResourceType.DRAWABLE; - case INTERPOLATOR: - return ResourceType.INTERPOLATOR; - case LAYOUT: - return ResourceType.LAYOUT; - case MENU: - return ResourceType.MENU; - case MIPMAP: - return ResourceType.MIPMAP; - case RAW: - return ResourceType.RAW; - case XML: - return ResourceType.XML; - case VALUES: - return null; - default: - assert false : folderType; - return null; - } - } -} |