diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:16 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:16 -0800 |
commit | 82ea7a177797b844b252effea5c7c7c5d63ea4ac (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide | |
parent | c9432be76d50a527da232d518f633add2f76242b (diff) | |
download | sdk-82ea7a177797b844b252effea5c7c7c5d63ea4ac.zip sdk-82ea7a177797b844b252effea5c7c7c5d63ea4ac.tar.gz sdk-82ea7a177797b844b252effea5c7c7c5d63ea4ac.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide')
250 files changed, 0 insertions, 58207 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java deleted file mode 100644 index 7304e5e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2007 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 com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer; - - -/** - * Constant definition class.<br> - * <br> - * Most constants have a prefix defining the content. - * <ul> - * <li><code>WS_</code> Workspace path constant. Those are absolute paths, - * from the project root.</li> - * <li><code>OS_</code> OS path constant. These paths are different depending on the platform.</li> - * <li><code>FN_</code> File name constant.</li> - * <li><code>FD_</code> Folder name constant.</li> - * <li><code>MARKER_</code> Resource Marker Ids constant.</li> - * <li><code>EXT_</code> File extension constant. This does NOT include a dot.</li> - * <li><code>DOT_</code> File extension constant. This start with a dot.</li> - * <li><code>RE_</code> Regexp constant.</li> - * <li><code>BUILD_</code> Build verbosity level constant. To use with - * <code>AdtPlugin.printBuildToConsole()</code></li> - * </ul> - */ -public class AdtConstants { - /** Generic marker for ADT errors. */ - public final static String MARKER_ADT = AdtPlugin.PLUGIN_ID + ".adtProblem"; //$NON-NLS-1$ - - /** Marker for Android Target errors. - * This is not cleared on each like other markers. Instead, it's cleared - * when an {@link AndroidClasspathContainerInitializer} has succeeded in creating an - * AndroidClasspathContainer */ - public final static String MARKER_TARGET = AdtPlugin.PLUGIN_ID + ".targetProblem"; //$NON-NLS-1$ - - /** Build verbosity "Always". Those messages are always displayed. */ - public final static int BUILD_ALWAYS = 0; - - /** Build verbosity level "Normal" */ - public final static int BUILD_NORMAL = 1; - - /** Build verbosity level "Verbose". Those messages are only displayed in verbose mode */ - public final static int BUILD_VERBOSE = 2; - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java deleted file mode 100644 index 9aa9354..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * Copyright (C) 2007 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 com.android.ddmuilib.StackTracePanel; -import com.android.ddmuilib.StackTracePanel.ISourceRevealer; -import com.android.ddmuilib.console.DdmConsole; -import com.android.ddmuilib.console.IDdmConsole; -import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController; -import com.android.ide.eclipse.adt.preferences.BuildPreferencePage; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.project.export.ExportWizard; -import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer; -import com.android.ide.eclipse.adt.sdk.AndroidTargetParser; -import com.android.ide.eclipse.adt.sdk.LoadStatus; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.EclipseUiHelper; -import com.android.ide.eclipse.common.SdkStatsHelper; -import com.android.ide.eclipse.common.StreamHelper; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.common.project.ExportHelper; -import com.android.ide.eclipse.common.project.ExportHelper.IExportCallback; -import com.android.ide.eclipse.ddms.DdmsPlugin; -import com.android.ide.eclipse.ddms.ImageLoader; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.layout.LayoutEditor; -import com.android.ide.eclipse.editors.menu.MenuEditor; -import com.android.ide.eclipse.editors.resources.ResourcesEditor; -import com.android.ide.eclipse.editors.resources.manager.ProjectResources; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolder; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener; -import com.android.ide.eclipse.editors.xml.XmlEditor; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Preferences; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.core.runtime.Preferences.IPropertyChangeListener; -import org.eclipse.core.runtime.Preferences.PropertyChangeEvent; -import org.eclipse.core.runtime.jobs.IJobChangeEvent; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.core.runtime.jobs.JobChangeAdapter; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IEditorDescriptor; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.console.ConsolePlugin; -import org.eclipse.ui.console.IConsole; -import org.eclipse.ui.console.IConsoleConstants; -import org.eclipse.ui.console.MessageConsole; -import org.eclipse.ui.console.MessageConsoleStream; -import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.part.FileEditorInput; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.osgi.framework.Version; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * The activator class controls the plug-in life cycle - */ -public class AdtPlugin extends AbstractUIPlugin { - /** The plug-in ID */ - public static final String PLUGIN_ID = "com.android.ide.eclipse.adt"; //$NON-NLS-1$ - - public final static String PREFS_SDK_DIR = PLUGIN_ID + ".sdk"; //$NON-NLS-1$ - - public final static String PREFS_RES_AUTO_REFRESH = PLUGIN_ID + ".resAutoRefresh"; //$NON-NLS-1$ - - public final static String PREFS_BUILD_VERBOSITY = PLUGIN_ID + ".buildVerbosity"; //$NON-NLS-1$ - - public final static String PREFS_DEFAULT_DEBUG_KEYSTORE = PLUGIN_ID + ".defaultDebugKeyStore"; //$NON-NLS-1$ - - public final static String PREFS_CUSTOM_DEBUG_KEYSTORE = PLUGIN_ID + ".customDebugKeyStore"; //$NON-NLS-1$ - - public final static String PREFS_HOME_PACKAGE = PLUGIN_ID + ".homePackage"; //$NON-NLS-1$ - - public final static String PREFS_EMU_OPTIONS = PLUGIN_ID + ".emuOptions"; //$NON-NLS-1$ - - /** singleton instance */ - private static AdtPlugin sPlugin; - - private static Image sAndroidLogo; - private static ImageDescriptor sAndroidLogoDesc; - - /** default store, provided by eclipse */ - private IPreferenceStore mStore; - - /** cached location for the sdk folder */ - private String mOsSdkLocation; - - /** The global android console */ - private MessageConsole mAndroidConsole; - - /** Stream to write in the android console */ - private MessageConsoleStream mAndroidConsoleStream; - - /** Stream to write error messages to the android console */ - private MessageConsoleStream mAndroidConsoleErrorStream; - - /** Image loader object */ - private ImageLoader mLoader; - - /** Verbosity of the build */ - private int mBuildVerbosity = AdtConstants.BUILD_NORMAL; - - /** Color used in the error console */ - private Color mRed; - - /** Load status of the SDK. Any access MUST be in a synchronized(mPostLoadProjects) block */ - private LoadStatus mSdkIsLoaded = LoadStatus.LOADING; - /** Project to update once the SDK is loaded. - * Any access MUST be in a synchronized(mPostLoadProjectsToResolve) block */ - private final ArrayList<IJavaProject> mPostLoadProjectsToResolve = - new ArrayList<IJavaProject>(); - /** Project to check validity of cache vs actual once the SDK is loaded. - * Any access MUST be in a synchronized(mPostLoadProjectsToResolve) block */ - private final ArrayList<IJavaProject> mPostLoadProjectsToCheck = new ArrayList<IJavaProject>(); - - private ResourceMonitor mResourceMonitor; - private ArrayList<Runnable> mResourceRefreshListener = new ArrayList<Runnable>(); - - /** - * Custom PrintStream for Dx output. This class overrides the method - * <code>println()</code> and adds the standard output tag with the - * date and the project name in front of every messages. - */ - private static final class AndroidPrintStream extends PrintStream { - private IProject mProject; - private String mPrefix; - - /** - * Default constructor with project and output stream. - * The project is used to get the project name for the output tag. - * - * @param project The Project - * @param prefix A prefix to be printed before the actual message. Can be null - * @param stream The Stream - */ - public AndroidPrintStream(IProject project, String prefix, OutputStream stream) { - super(stream); - mProject = project; - } - - @Override - public void println(String message) { - // write the date/project tag first. - String tag = StreamHelper.getMessageTag(mProject != null ? mProject.getName() : null); - - print(tag); - if (mPrefix != null) { - print(mPrefix); - } - - // then write the regular message - super.println(message); - } - } - - /** - * An error handler for checkSdkLocationAndId() that will handle the generated error - * or warning message. Each method must return a boolean that will in turn be returned by - * checkSdkLocationAndId. - */ - public static abstract class CheckSdkErrorHandler { - /** Handle an error message during sdk location check. Returns whatever - * checkSdkLocationAndId() should returns. - */ - public abstract boolean handleError(String message); - - /** Handle a warning message during sdk location check. Returns whatever - * checkSdkLocationAndId() should returns. - */ - public abstract boolean handleWarning(String message); - } - - /** - * The constructor - */ - public AdtPlugin() { - sPlugin = this; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) - */ - @Override - public void start(BundleContext context) throws Exception { - super.start(context); - - Display display = getDisplay(); - - // set the default android console. - mAndroidConsole = new MessageConsole("Android", null); //$NON-NLS-1$ - ConsolePlugin.getDefault().getConsoleManager().addConsoles( - new IConsole[] { mAndroidConsole }); - - // get the stream to write in the android console. - mAndroidConsoleStream = mAndroidConsole.newMessageStream(); - mAndroidConsoleErrorStream = mAndroidConsole.newMessageStream(); - mRed = new Color(display, 0xFF, 0x00, 0x00); - - // because this can be run, in some cases, by a non ui thread, and beccause - // changing the console properties update the ui, we need to make this change - // in the ui thread. - display.asyncExec(new Runnable() { - public void run() { - mAndroidConsoleErrorStream.setColor(mRed); - } - }); - - // set up the ddms console to use this objects - DdmConsole.setConsole(new IDdmConsole() { - public void printErrorToConsole(String message) { - AdtPlugin.printErrorToConsole((String)null, message); - } - public void printErrorToConsole(String[] messages) { - AdtPlugin.printErrorToConsole((String)null, (Object[])messages); - } - public void printToConsole(String message) { - AdtPlugin.printToConsole((String)null, message); - } - public void printToConsole(String[] messages) { - AdtPlugin.printToConsole((String)null, (Object[])messages); - } - }); - - // get the eclipse store - mStore = getPreferenceStore(); - - // set the listener for the preference change - Preferences prefs = getPluginPreferences(); - prefs.addPropertyChangeListener(new IPropertyChangeListener() { - public void propertyChange(PropertyChangeEvent event) { - // get the name of the property that changed. - String property = event.getProperty(); - - // if the SDK changed, we update the cached version - if (PREFS_SDK_DIR.equals(property)) { - - // get the new one from the preferences - mOsSdkLocation = (String)event.getNewValue(); - - // make sure it ends with a separator - if (mOsSdkLocation.endsWith(File.separator) == false) { - mOsSdkLocation = mOsSdkLocation + File.separator; - } - - // finally restart adb, in case it's a different version - DdmsPlugin.setAdb(getOsAbsoluteAdb(), true /* startAdb */); - - // get the SDK location and build id. - if (checkSdkLocationAndId()) { - // if sdk if valid, reparse it - - // add all the opened Android projects to the list of projects to be updated - // after the SDK is reloaded - synchronized (getSdkLockObject()) { - // get the project to refresh. - IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(); - mPostLoadProjectsToResolve.addAll(Arrays.asList(androidProjects)); - } - - // parse the SDK resources at the new location - parseSdkContent(); - } - } else if (PREFS_BUILD_VERBOSITY.equals(property)) { - mBuildVerbosity = BuildPreferencePage.getBuildLevel( - mStore.getString(PREFS_BUILD_VERBOSITY)); - } - } - }); - - mOsSdkLocation = mStore.getString(PREFS_SDK_DIR); - - // make sure it ends with a separator. Normally this is done when the preference - // is set. But to make sure older version still work, we fix it here as well. - if (mOsSdkLocation.length() > 0 && mOsSdkLocation.endsWith(File.separator) == false) { - mOsSdkLocation = mOsSdkLocation + File.separator; - } - - // check the location of SDK - final boolean isSdkLocationValid = checkSdkLocationAndId(); - - mBuildVerbosity = BuildPreferencePage.getBuildLevel( - mStore.getString(PREFS_BUILD_VERBOSITY)); - - // create the loader that's able to load the images - mLoader = new ImageLoader(this); - - // start the DdmsPlugin by setting the adb location, only if it is set already. - if (mOsSdkLocation.length() > 0) { - DdmsPlugin.setAdb(getOsAbsoluteAdb(), true); - } - - // and give it the debug launcher for android projects - DdmsPlugin.setRunningAppDebugLauncher(new DdmsPlugin.IDebugLauncher() { - public boolean debug(String appName, int port) { - // search for an android project matching the process name - IProject project = ProjectHelper.findAndroidProjectByAppName(appName); - if (project != null) { - AndroidLaunchController.debugRunningApp(project, port); - return true; - } else { - return false; - } - } - }); - - StackTracePanel.setSourceRevealer(new ISourceRevealer() { - public void reveal(String applicationName, String className, int line) { - IProject project = ProjectHelper.findAndroidProjectByAppName(applicationName); - if (project != null) { - BaseProjectHelper.revealSource(project, className, line); - } - } - }); - - // setup export callback for editors - ExportHelper.setCallback(new IExportCallback() { - public void startExportWizard(IProject project) { - StructuredSelection selection = new StructuredSelection(project); - - ExportWizard wizard = new ExportWizard(); - wizard.init(PlatformUI.getWorkbench(), selection); - WizardDialog dialog = new WizardDialog(getDisplay().getActiveShell(), - wizard); - dialog.open(); - } - }); - - // initialize editors - startEditors(); - - // Ping the usage server and parse the SDK content. - // This is deferred in separate jobs to avoid blocking the bundle start. - // We also serialize them to avoid too many parallel jobs when Eclipse starts. - Job pingJob = createPingUsageServerJob(); - pingJob.addJobChangeListener(new JobChangeAdapter() { - @Override - public void done(IJobChangeEvent event) { - super.done(event); - - // Once the ping job is finished, start the SDK parser - if (isSdkLocationValid) { - // parse the SDK resources. - parseSdkContent(); - } - } - }); - // build jobs are run after other interactive jobs - pingJob.setPriority(Job.BUILD); - // Wait 2 seconds before starting the ping job. This leaves some time to the - // other bundles to initialize. - pingJob.schedule(2000 /*milliseconds*/); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) - */ - @Override - public void stop(BundleContext context) throws Exception { - super.stop(context); - - stopEditors(); - - mRed.dispose(); - synchronized (AdtPlugin.class) { - sPlugin = null; - } - } - - /** Return the image loader for the plugin */ - public static synchronized ImageLoader getImageLoader() { - if (sPlugin != null) { - return sPlugin.mLoader; - } - return null; - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static synchronized AdtPlugin getDefault() { - return sPlugin; - } - - public static Display getDisplay() { - IWorkbench bench = null; - synchronized (AdtPlugin.class) { - bench = sPlugin.getWorkbench(); - } - - if (bench != null) { - return bench.getDisplay(); - } - return null; - } - - /** Returns the adb path relative to the sdk folder */ - public static String getOsRelativeAdb() { - return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_ADB; - } - - /** Returns the emulator path relative to the sdk folder */ - public static String getOsRelativeEmulator() { - return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_EMULATOR; - } - - /** Returns the absolute adb path */ - public static String getOsAbsoluteAdb() { - return getOsSdkFolder() + getOsRelativeAdb(); - } - - /** Returns the absolute traceview path */ - public static String getOsAbsoluteTraceview() { - return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER + - AndroidConstants.FN_TRACEVIEW; - } - - /** Returns the absolute emulator path */ - public static String getOsAbsoluteEmulator() { - return getOsSdkFolder() + getOsRelativeEmulator(); - } - - /** - * Returns a Url file path to the javaDoc folder. - */ - public static String getUrlDoc() { - return ProjectHelper.getJavaDocPath( - getOsSdkFolder() + AndroidConstants.WS_JAVADOC_FOLDER_LEAF); - } - - /** - * Returns the SDK folder. - * Guaranteed to be terminated by a platform-specific path separator. - */ - public static synchronized String getOsSdkFolder() { - if (sPlugin == null) { - return null; - } - - if (sPlugin.mOsSdkLocation == null) { - sPlugin.mOsSdkLocation = sPlugin.mStore.getString(PREFS_SDK_DIR); - } - return sPlugin.mOsSdkLocation; - } - - public static String getOsSdkToolsFolder() { - return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER; - } - - public static synchronized boolean getAutoResRefresh() { - if (sPlugin == null) { - return false; - } - return sPlugin.mStore.getBoolean(PREFS_RES_AUTO_REFRESH); - } - - public static synchronized int getBuildVerbosity() { - if (sPlugin != null) { - return sPlugin.mBuildVerbosity; - } - - return 0; - } - - /** - * Returns an image descriptor for the image file at the given - * plug-in relative path - * - * @param path the path - * @return the image descriptor - */ - public static ImageDescriptor getImageDescriptor(String path) { - return imageDescriptorFromPlugin(PLUGIN_ID, path); - } - - /** - * Reads and returns the content of a text file embedded in the plugin jar - * file. - * @param filepath the file path to the text file - * @return null if the file could not be read - */ - public static String readEmbeddedTextFile(String filepath) { - Bundle bundle = null; - synchronized (AdtPlugin.class) { - if (sPlugin != null) { - bundle = sPlugin.getBundle(); - } else { - return null; - } - } - - // attempt to get a file to one of the template. - try { - URL url = bundle.getEntry(AndroidConstants.WS_SEP + filepath); - if (url != null) { - BufferedReader reader = new BufferedReader( - new InputStreamReader(url.openStream())); - - String line; - StringBuilder total = new StringBuilder(reader.readLine()); - while ((line = reader.readLine()) != null) { - total.append('\n'); - total.append(line); - } - - return total.toString(); - } - } catch (MalformedURLException e) { - // we'll just return null. - } catch (IOException e) { - // we'll just return null. - } - - return null; - } - - /** - * Reads and returns the content of a binary file embedded in the plugin jar - * file. - * @param filepath the file path to the text file - * @return null if the file could not be read - */ - public static byte[] readEmbeddedFile(String filepath) { - Bundle bundle = null; - synchronized (AdtPlugin.class) { - if (sPlugin != null) { - bundle = sPlugin.getBundle(); - } else { - return null; - } - } - - // attempt to get a file to one of the template. - try { - URL url = bundle.getEntry(AndroidConstants.WS_SEP + filepath); - if (url != null) { - // create a buffered reader to facilitate reading. - BufferedInputStream stream = new BufferedInputStream( - url.openStream()); - - // get the size to read. - int avail = stream.available(); - - // create the buffer and reads it. - byte[] buffer = new byte[avail]; - stream.read(buffer); - - // and return. - return buffer; - } - } catch (MalformedURLException e) { - // we'll just return null. - } catch (IOException e) { - // we'll just return null;. - } - - return null; - } - - /** - * Displays an error dialog box. This dialog box is ran asynchronously in the ui thread, - * therefore this method can be called from any thread. - * @param title The title of the dialog box - * @param message The error message - */ - public final static void displayError(final String title, final String message) { - // get the current Display - final Display display = getDisplay(); - - // dialog box only run in ui thread.. - display.asyncExec(new Runnable() { - public void run() { - Shell shell = display.getActiveShell(); - MessageDialog.openError(shell, title, message); - } - }); - } - - /** - * Displays a warning dialog box. This dialog box is ran asynchronously in the ui thread, - * therefore this method can be called from any thread. - * @param title The title of the dialog box - * @param message The warning message - */ - public final static void displayWarning(final String title, final String message) { - // get the current Display - final Display display = getDisplay(); - - // dialog box only run in ui thread.. - display.asyncExec(new Runnable() { - public void run() { - Shell shell = display.getActiveShell(); - MessageDialog.openWarning(shell, title, message); - } - }); - } - - /** - * Display a yes/no question dialog box. This dialog is opened synchronously in the ui thread, - * therefore this message can be called from any thread. - * @param title The title of the dialog box - * @param message The error message - * @return true if OK was clicked. - */ - public final static boolean displayPrompt(final String title, final String message) { - // get the current Display and Shell - final Display display = getDisplay(); - - // we need to ask the user what he wants to do. - final boolean[] result = new boolean[1]; - display.syncExec(new Runnable() { - public void run() { - Shell shell = display.getActiveShell(); - result[0] = MessageDialog.openQuestion(shell, title, message); - } - }); - return result[0]; - } - - /** - * Logs a message to the default Eclipse log. - * - * @param severity The severity code. Valid values are: {@link IStatus#OK}, - * {@link IStatus#ERROR}, {@link IStatus#INFO}, {@link IStatus#WARNING} or - * {@link IStatus#CANCEL}. - * @param format The format string, like for {@link String#format(String, Object...)}. - * @param args The arguments for the format string, like for - * {@link String#format(String, Object...)}. - */ - public static void log(int severity, String format, Object ... args) { - String message = String.format(format, args); - Status status = new Status(severity, PLUGIN_ID, message); - getDefault().getLog().log(status); - } - - /** - * Logs an exception to the default Eclipse log. - * <p/> - * The status severity is always set to ERROR. - * - * @param exception the exception to log. - * @param format The format string, like for {@link String#format(String, Object...)}. - * @param args The arguments for the format string, like for - * {@link String#format(String, Object...)}. - */ - public static void log(Throwable exception, String format, Object ... args) { - String message = String.format(format, args); - Status status = new Status(IStatus.ERROR, PLUGIN_ID, message, exception); - getDefault().getLog().log(status); - } - - /** - * This is a mix between log(Throwable) and printErrorToConsole. - * <p/> - * This logs the exception with an ERROR severity and the given printf-like format message. - * The same message is then printed on the Android error console with the associated tag. - * - * @param exception the exception to log. - * @param format The format string, like for {@link String#format(String, Object...)}. - * @param args The arguments for the format string, like for - * {@link String#format(String, Object...)}. - */ - public static synchronized void logAndPrintError(Throwable exception, String tag, - String format, Object ... args) { - if (sPlugin != null) { - String message = String.format(format, args); - Status status = new Status(IStatus.ERROR, PLUGIN_ID, message, exception); - getDefault().getLog().log(status); - StreamHelper.printToStream(sPlugin.mAndroidConsoleErrorStream, tag, message); - showAndroidConsole(); - } - } - - /** - * Prints one or more error message to the android console. - * @param tag A tag to be associated with the message. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static synchronized void printErrorToConsole(String tag, Object... objects) { - if (sPlugin != null) { - StreamHelper.printToStream(sPlugin.mAndroidConsoleErrorStream, tag, objects); - - showAndroidConsole(); - } - } - - /** - * Prints one or more error message to the android console. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static void printErrorToConsole(Object... objects) { - printErrorToConsole((String)null, objects); - } - - /** - * Prints one or more error message to the android console. - * @param project The project to which the message is associated. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static void printErrorToConsole(IProject project, Object... objects) { - String tag = project != null ? project.getName() : null; - printErrorToConsole(tag, objects); - } - - /** - * Prints one or more build messages to the android console, filtered by Build output verbosity. - * @param level Verbosity level of the message. - * @param project The project to which the message is associated. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - * @see AdtConstants#BUILD_ALWAYS - * @see AdtConstants#BUILD_NORMAL - * @see AdtConstants#BUILD_VERBOSE - */ - public static synchronized void printBuildToConsole(int level, IProject project, - Object... objects) { - if (sPlugin != null) { - if (level <= sPlugin.mBuildVerbosity) { - String tag = project != null ? project.getName() : null; - StreamHelper.printToStream(sPlugin.mAndroidConsoleStream, tag, objects); - } - } - } - - /** - * Prints one or more message to the android console. - * @param tag The tag to be associated with the message. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static synchronized void printToConsole(String tag, Object... objects) { - if (sPlugin != null) { - StreamHelper.printToStream(sPlugin.mAndroidConsoleStream, tag, objects); - } - } - - /** - * Prints one or more message to the android console. - * @param project The project to which the message is associated. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static void printToConsole(IProject project, Object... objects) { - String tag = project != null ? project.getName() : null; - printToConsole(tag, objects); - } - - /** Force the display of the android console */ - public static void showAndroidConsole() { - // first make sure the console is in the workbench - EclipseUiHelper.showView(IConsoleConstants.ID_CONSOLE_VIEW, true); - - // now make sure it's not docked. - ConsolePlugin.getDefault().getConsoleManager().showConsoleView( - AdtPlugin.getDefault().getAndroidConsole()); - } - - /** - * Returns an standard PrintStream object for a specific project.<br> - * This PrintStream will add a date/project at the beginning of every - * <code>println()</code> output. - * - * @param project The project object - * @param prefix The prefix to be added to the message. Can be null. - * @return a new PrintStream - */ - public static synchronized PrintStream getOutPrintStream(IProject project, String prefix) { - if (sPlugin != null) { - return new AndroidPrintStream(project, prefix, sPlugin.mAndroidConsoleStream); - } - - return null; - } - - /** - * Returns an error PrintStream object for a specific project.<br> - * This PrintStream will add a date/project at the beginning of every - * <code>println()</code> output. - * - * @param project The project object - * @param prefix The prefix to be added to the message. Can be null. - * @return a new PrintStream - */ - public static synchronized PrintStream getErrPrintStream(IProject project, String prefix) { - if (sPlugin != null) { - return new AndroidPrintStream(project, prefix, sPlugin.mAndroidConsoleErrorStream); - } - - return null; - } - - /** - * Returns whether the Sdk has been loaded. - */ - public final LoadStatus getSdkLoadStatus() { - synchronized (getSdkLockObject()) { - return mSdkIsLoaded; - } - } - - /** - * Returns the lock object for SDK loading. If you wish to do things while the SDK is loading, - * you must synchronize on this object. - * @return - */ - public final Object getSdkLockObject() { - return mPostLoadProjectsToResolve; - } - - /** - * Sets the given {@link IJavaProject} to have its target resolved again once the SDK finishes - * to load. - */ - public final void setProjectToResolve(IJavaProject javaProject) { - synchronized (getSdkLockObject()) { - mPostLoadProjectsToResolve.add(javaProject); - } - } - - /** - * Sets the given {@link IJavaProject} to have its target checked for consistency - * once the SDK finishes to load. This is used if the target is resolved using cached - * information while the SDK is loading. - */ - public final void setProjectToCheck(IJavaProject javaProject) { - // only lock on - synchronized (getSdkLockObject()) { - mPostLoadProjectsToCheck.add(javaProject); - } - } - - /** - * Checks the location of the SDK is valid and if it is, grab the SDK API version - * from the SDK. - * @return false if the location is not correct. - */ - private boolean checkSdkLocationAndId() { - if (mOsSdkLocation == null || mOsSdkLocation.length() == 0) { - displayError(Messages.Dialog_Title_SDK_Location, Messages.SDK_Not_Setup); - return false; - } - - return checkSdkLocationAndId(mOsSdkLocation, new CheckSdkErrorHandler() { - @Override - public boolean handleError(String message) { - AdtPlugin.displayError(Messages.Dialog_Title_SDK_Location, - String.format(Messages.Error_Check_Prefs, message)); - return false; - } - - @Override - public boolean handleWarning(String message) { - AdtPlugin.displayWarning(Messages.Dialog_Title_SDK_Location, message); - return true; - } - }); - } - - /** - * Internal helper to perform the actual sdk location and id check. - * - * @param osSdkLocation The sdk directory, an OS path. - * @param errorHandler An checkSdkErrorHandler that can display a warning or an error. - * @return False if there was an error or the result from the errorHandler invocation. - */ - public boolean checkSdkLocationAndId(String osSdkLocation, CheckSdkErrorHandler errorHandler) { - if (osSdkLocation.endsWith(File.separator) == false) { - osSdkLocation = osSdkLocation + File.separator; - } - - File osSdkFolder = new File(osSdkLocation); - if (osSdkFolder.isDirectory() == false) { - return errorHandler.handleError( - String.format(Messages.Could_Not_Find_Folder, osSdkLocation)); - } - - String osTools = osSdkLocation + SdkConstants.OS_SDK_TOOLS_FOLDER; - File toolsFolder = new File(osTools); - if (toolsFolder.isDirectory() == false) { - return errorHandler.handleError( - String.format(Messages.Could_Not_Find_Folder_In_SDK, - SdkConstants.FD_TOOLS, osSdkLocation)); - } - - // check the path to various tools we use - String[] filesToCheck = new String[] { - osSdkLocation + getOsRelativeAdb(), - osSdkLocation + getOsRelativeEmulator() - }; - for (String file : filesToCheck) { - if (checkFile(file) == false) { - return errorHandler.handleError(String.format(Messages.Could_Not_Find, file)); - } - } - - // check the SDK build id/version and the plugin version. - return VersionCheck.checkVersion(osSdkLocation, errorHandler); - } - - /** - * Checks if a path reference a valid existing file. - * @param osPath the os path to check. - * @return true if the file exists and is, in fact, a file. - */ - private boolean checkFile(String osPath) { - File file = new File(osPath); - if (file.isFile() == false) { - return false; - } - - return true; - } - - /** - * Creates a job than can ping the usage server. - */ - private Job createPingUsageServerJob() { - // In order to not block the plugin loading, so we spawn another thread. - Job job = new Job("Android SDK Ping") { // Job name, visible in progress view - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - - // get the version of the plugin - String versionString = (String) getBundle().getHeaders().get( - Constants.BUNDLE_VERSION); - Version version = new Version(versionString); - - SdkStatsHelper.pingUsageServer("editors", version); //$NON-NLS-1$ - - return Status.OK_STATUS; - } catch (Throwable t) { - log(t, "pingUsageServer failed"); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PLUGIN_ID, - "pingUsageServer failed", t); - } - } - }; - return job; - } - - /** - * Parses the SDK resources. - */ - private void parseSdkContent() { - // Perform the update in a thread (here an Eclipse runtime job) - // since this should never block the caller (especially the start method) - Job job = new Job(Messages.AdtPlugin_Android_SDK_Content_Loader) { - @SuppressWarnings("unchecked") - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - SubMonitor progress = SubMonitor.convert(monitor, - "Initialize SDK Manager", 100); - - Sdk sdk = Sdk.loadSdk(mOsSdkLocation); - - if (sdk != null) { - - progress.setTaskName(Messages.AdtPlugin_Parsing_Resources); - - for (IAndroidTarget target : sdk.getTargets()) { - IStatus status = new AndroidTargetParser(target).run(progress); - if (status.getCode() != IStatus.OK) { - synchronized (getSdkLockObject()) { - mSdkIsLoaded = LoadStatus.FAILED; - mPostLoadProjectsToResolve.clear(); - } - return status; - } - } - - // FIXME: move this per platform, or somewhere else. - progress = SubMonitor.convert(monitor, - Messages.AdtPlugin_Parsing_Resources, 20); - - synchronized (getSdkLockObject()) { - mSdkIsLoaded = LoadStatus.LOADED; - - // check the projects that need checking. - // The method modifies the list (it removes the project that - // do not need to be resolved again). - AndroidClasspathContainerInitializer.checkProjectsCache( - mPostLoadProjectsToCheck); - - mPostLoadProjectsToResolve.addAll(mPostLoadProjectsToCheck); - - // update the project that needs recompiling. - if (mPostLoadProjectsToResolve.size() > 0) { - IJavaProject[] array = mPostLoadProjectsToResolve.toArray( - new IJavaProject[mPostLoadProjectsToResolve.size()]); - AndroidClasspathContainerInitializer.updateProjects(array); - mPostLoadProjectsToResolve.clear(); - } - } - } - - // Notify resource changed listeners - progress.subTask("Refresh UI"); - progress.setWorkRemaining(mResourceRefreshListener.size()); - - // Clone the list before iterating, to avoid Concurrent Modification - // exceptions - List<Runnable> listeners = (List<Runnable>)mResourceRefreshListener.clone(); - for (Runnable listener : listeners) { - try { - AdtPlugin.getDisplay().syncExec(listener); - } catch (Exception e) { - AdtPlugin.log(e, "ResourceRefreshListener Failed"); //$NON-NLS-1$ - } finally { - progress.worked(1); - } - } - } finally { - if (monitor != null) { - monitor.done(); - } - } - - return Status.OK_STATUS; - } - }; - job.setPriority(Job.BUILD); // build jobs are run after other interactive jobs - job.schedule(); - } - - /** Returns the global android console */ - public MessageConsole getAndroidConsole() { - return mAndroidConsole; - } - - // ----- Methods for Editors ------- - - public void startEditors() { - sAndroidLogoDesc = imageDescriptorFromPlugin(AdtPlugin.PLUGIN_ID, - "/icons/android.png"); //$NON-NLS-1$ - sAndroidLogo = sAndroidLogoDesc.createImage(); - - // get the stream to write in the android console. - MessageConsole androidConsole = AdtPlugin.getDefault().getAndroidConsole(); - mAndroidConsoleStream = androidConsole.newMessageStream(); - - mAndroidConsoleErrorStream = androidConsole.newMessageStream(); - mRed = new Color(getDisplay(), 0xFF, 0x00, 0x00); - - // because this can be run, in some cases, by a non ui thread, and beccause - // changing the console properties update the ui, we need to make this change - // in the ui thread. - getDisplay().asyncExec(new Runnable() { - public void run() { - mAndroidConsoleErrorStream.setColor(mRed); - } - }); - - // Add a resource listener to handle compiled resources. - IWorkspace ws = ResourcesPlugin.getWorkspace(); - mResourceMonitor = ResourceMonitor.startMonitoring(ws); - - if (mResourceMonitor != null) { - try { - setupDefaultEditor(mResourceMonitor); - ResourceManager.setup(mResourceMonitor); - } catch (Throwable t) { - log(t, "ResourceManager.setup failed"); //$NON-NLS-1$ - } - } - } - - /** - * The <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code> - * method saves this plug-in's preference and dialog stores and shuts down - * its image registry (if they are in use). Subclasses may extend this - * method, but must send super <b>last</b>. A try-finally statement should - * be used where necessary to ensure that <code>super.shutdown()</code> is - * always done. - * - * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) - */ - public void stopEditors() { - sAndroidLogo.dispose(); - - IconFactory.getInstance().Dispose(); - - // Remove the resource listener that handles compiled resources. - IWorkspace ws = ResourcesPlugin.getWorkspace(); - ResourceMonitor.stopMonitoring(ws); - - mRed.dispose(); - } - - /** - * Returns an Image for the small Android logo. - * - * Callers should not dispose it. - */ - public static Image getAndroidLogo() { - return sAndroidLogo; - } - - /** - * Returns an {@link ImageDescriptor} for the small Android logo. - * - * Callers should not dispose it. - */ - public static ImageDescriptor getAndroidLogoDesc() { - return sAndroidLogoDesc; - } - - /** - * Returns the ResourceMonitor object. - */ - public ResourceMonitor getResourceMonitor() { - return mResourceMonitor; - } - - /** - * Sets up the editor to register default editors for resource files when needed. - * - * This is called by the {@link AdtPlugin} during initialization. - * - * @param monitor The main Resource Monitor object. - */ - public void setupDefaultEditor(ResourceMonitor monitor) { - monitor.addFileListener(new IFileListener() { - - private static final String UNKNOWN_EDITOR = "unknown-editor"; //$NON-NLS-1$ - - /* (non-Javadoc) - * Sent when a file changed. - * @param file The file that changed. - * @param markerDeltas The marker deltas for the file. - * @param kind The change kind. This is equivalent to - * {@link IResourceDelta#accept(IResourceDeltaVisitor)} - * - * @see IFileListener#fileChanged - */ - public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { - if (AndroidConstants.EXT_XML.equals(file.getFileExtension())) { - // The resources files must have a file path similar to - // project/res/.../*.xml - // There is no support for sub folders, so the segment count must be 4 - if (file.getFullPath().segmentCount() == 4) { - // check if we are inside the res folder. - String segment = file.getFullPath().segment(1); - if (segment.equalsIgnoreCase(SdkConstants.FD_RESOURCES)) { - // we are inside a res/ folder, get the actual ResourceFolder - ProjectResources resources = ResourceManager.getInstance(). - getProjectResources(file.getProject()); - - // This happens when importing old Android projects in Eclipse - // that lack the container (probably because resources fail to build - // properly.) - if (resources == null) { - log(IStatus.INFO, - "getProjectResources failed for path %1$s in project %2$s", //$NON-NLS-1$ - file.getFullPath().toOSString(), - file.getProject().getName()); - return; - } - - ResourceFolder resFolder = resources.getResourceFolder( - (IFolder)file.getParent()); - - if (resFolder != null) { - if (kind == IResourceDelta.ADDED) { - resourceAdded(file, resFolder.getType()); - } else if (kind == IResourceDelta.CHANGED) { - resourceChanged(file, resFolder.getType()); - } - } else { - // if the res folder is null, this means the name is invalid, - // in this case we remove whatever android editors that was set - // as the default editor. - IEditorDescriptor desc = IDE.getDefaultEditor(file); - String editorId = desc.getId(); - if (editorId.startsWith(AndroidConstants.EDITORS_NAMESPACE)) { - // reset the default editor. - IDE.setDefaultEditor(file, null); - } - } - } - } - } - } - - private void resourceAdded(IFile file, ResourceFolderType type) { - // set the default editor based on the type. - if (type == ResourceFolderType.LAYOUT) { - IDE.setDefaultEditor(file, LayoutEditor.ID); - } else if (type == ResourceFolderType.DRAWABLE - || type == ResourceFolderType.VALUES) { - IDE.setDefaultEditor(file, ResourcesEditor.ID); - } else if (type == ResourceFolderType.MENU) { - IDE.setDefaultEditor(file, MenuEditor.ID); - } else if (type == ResourceFolderType.XML) { - if (XmlEditor.canHandleFile(file)) { - IDE.setDefaultEditor(file, XmlEditor.ID); - } else { - // set a property to determine later if the XML can be handled - QualifiedName qname = new QualifiedName( - AdtPlugin.PLUGIN_ID, - UNKNOWN_EDITOR); - try { - file.setPersistentProperty(qname, "1"); - } catch (CoreException e) { - // pass - } - } - } - } - - private void resourceChanged(IFile file, ResourceFolderType type) { - if (type == ResourceFolderType.XML) { - IEditorDescriptor ed = IDE.getDefaultEditor(file); - if (ed == null || ed.getId() != XmlEditor.ID) { - QualifiedName qname = new QualifiedName( - AdtPlugin.PLUGIN_ID, - UNKNOWN_EDITOR); - String prop = null; - try { - prop = file.getPersistentProperty(qname); - } catch (CoreException e) { - // pass - } - if (prop != null && XmlEditor.canHandleFile(file)) { - try { - // remove the property & set editor - file.setPersistentProperty(qname, null); - IWorkbenchPage page = PlatformUI.getWorkbench(). - getActiveWorkbenchWindow().getActivePage(); - - IEditorPart oldEditor = page.findEditor(new FileEditorInput(file)); - if (oldEditor != null && - AdtPlugin.displayPrompt("Android XML Editor", - String.format("The file you just saved as been recognized as a file that could be better handled using the Android XML Editor. Do you want to edit '%1$s' using the Android XML editor instead?", - file.getFullPath()))) { - IDE.setDefaultEditor(file, XmlEditor.ID); - IEditorPart newEditor = page.openEditor( - new FileEditorInput(file), - XmlEditor.ID, - true, /* activate */ - IWorkbenchPage.MATCH_NONE); - - if (newEditor != null) { - page.closeEditor(oldEditor, true /* save */); - } - } - } catch (CoreException e) { - // setPersistentProperty or page.openEditor may have failed - } - } - } - } - } - - }, IResourceDelta.ADDED | IResourceDelta.CHANGED); - } - - public void addResourceChangedListener(Runnable resourceRefreshListener) { - mResourceRefreshListener.add(resourceRefreshListener); - } - - public void removeResourceChangedListener(Runnable resourceRefreshListener) { - mResourceRefreshListener.remove(resourceRefreshListener); - } - - public static synchronized OutputStream getErrorStream() { - return sPlugin.mAndroidConsoleErrorStream; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/Messages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/Messages.java deleted file mode 100644 index a638810..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/Messages.java +++ /dev/null @@ -1,48 +0,0 @@ - -package com.android.ide.eclipse.adt; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS { - private static final String BUNDLE_NAME = "com.android.ide.eclipse.adt.messages"; //$NON-NLS-1$ - - public static String AdtPlugin_Android_SDK_Content_Loader; - - public static String AdtPlugin_Android_SDK_Resource_Parser; - - public static String AdtPlugin_Failed_To_Parse_s; - - public static String AdtPlugin_Failed_To_Start_s; - - public static String AdtPlugin_Parsing_Resources; - - public static String Could_Not_Find; - - public static String Could_Not_Find_Folder; - - public static String Could_Not_Find_Folder_In_SDK; - - public static String Dialog_Title_SDK_Location; - - public static String Error_Check_Prefs; - - public static String SDK_Not_Setup; - - public static String VersionCheck_Plugin_Too_Old; - - public static String VersionCheck_Plugin_Version_Failed; - - public static String VersionCheck_SDK_Build_Too_Low; - - public static String VersionCheck_SDK_Milestone_Too_Low; - - public static String VersionCheck_Unable_To_Parse_Version_s; - - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/VersionCheck.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/VersionCheck.java deleted file mode 100644 index 6d85af3..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/VersionCheck.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2007 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 com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; -import com.android.sdklib.SdkConstants; - -import org.osgi.framework.Constants; -import org.osgi.framework.Version; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Class handling the version check for the plugin vs. the SDK.<br> - * The plugin must be able to support all version of the SDK. - * - * <p/>An SDK can require a new version of the plugin. - * <p/>The SDK contains a file with the minimum version for the plugin. This file is inside the - * <code>tools/lib</code> directory, and is called <code>plugin.prop</code>.<br> - * Inside that text file, there is a line in the format "plugin.version=#.#.#". This is checked - * against the current plugin version.<br> - * - */ -final class VersionCheck { - /** - * Pattern to get the minimum plugin version supported by the SDK. This is read from - * the file <code>$SDK/tools/lib/plugin.prop</code>. - */ - private final static Pattern sPluginVersionPattern = Pattern.compile( - "^plugin.version=(\\d+)\\.(\\d+)\\.(\\d+).*$"); //$NON-NLS-1$ - - /** - * Checks the plugin and the SDK have compatible versions. - * @param osSdkPath The path to the SDK - * @return true if compatible. - */ - public static boolean checkVersion(String osSdkPath, CheckSdkErrorHandler errorHandler) { - AdtPlugin plugin = AdtPlugin.getDefault(); - String osLibs = osSdkPath + SdkConstants.OS_SDK_TOOLS_LIB_FOLDER; - - // get the plugin property file, and grab the minimum plugin version required - // to work with the sdk - int minMajorVersion = -1; - int minMinorVersion = -1; - int minMicroVersion = -1; - try { - FileReader reader = new FileReader(osLibs + SdkConstants.FN_PLUGIN_PROP); - BufferedReader bReader = new BufferedReader(reader); - String line; - while ((line = bReader.readLine()) != null) { - Matcher m = sPluginVersionPattern.matcher(line); - if (m.matches()) { - minMajorVersion = Integer.parseInt(m.group(1)); - minMinorVersion = Integer.parseInt(m.group(2)); - minMicroVersion = Integer.parseInt(m.group(3)); - break; - } - } - } catch (FileNotFoundException e) { - // the build id will be null, and this is handled by the builders. - } catch (IOException e) { - // the build id will be null, and this is handled by the builders. - } - - // Failed to get the min plugin version number? - if (minMajorVersion == -1 || minMinorVersion == -1 || minMicroVersion ==-1) { - return errorHandler.handleWarning(Messages.VersionCheck_Plugin_Version_Failed); - } - - // test the plugin number - String versionString = (String) plugin.getBundle().getHeaders().get( - Constants.BUNDLE_VERSION); - Version version = new Version(versionString); - - boolean valid = true; - if (version.getMajor() < minMajorVersion) { - valid = false; - } else if (version.getMajor() == minMajorVersion) { - if (version.getMinor() < minMinorVersion) { - valid = false; - } else if (version.getMinor() == minMinorVersion) { - if (version.getMicro() < minMicroVersion) { - valid = false; - } - } - } - - if (valid == false) { - return errorHandler.handleWarning( - String.format(Messages.VersionCheck_Plugin_Too_Old, - minMajorVersion, minMinorVersion, minMicroVersion, versionString)); - } - - return true; // no error! - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java deleted file mode 100644 index 96068c2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * Copyright (C) 2007 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.build; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.jarutils.DebugKeyProvider; -import com.android.jarutils.JavaResourceFilter; -import com.android.jarutils.SignedJarBuilder; -import com.android.jarutils.DebugKeyProvider.IKeyGenOutput; -import com.android.jarutils.DebugKeyProvider.KeytoolException; -import com.android.jarutils.SignedJarBuilder.IZipEntryFilter; -import com.android.prefs.AndroidLocation.AndroidLocationException; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -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.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -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.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.preference.IPreferenceStore; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.security.GeneralSecurityException; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -public class ApkBuilder extends BaseBuilder { - - public static final String ID = "com.android.ide.eclipse.adt.ApkBuilder"; //$NON-NLS-1$ - - private static final String PROPERTY_CONVERT_TO_DEX = "convertToDex"; //$NON-NLS-1$ - private static final String PROPERTY_PACKAGE_RESOURCES = "packageResources"; //$NON-NLS-1$ - private static final String PROPERTY_BUILD_APK = "buildApk"; //$NON-NLS-1$ - - private static final String DX_PREFIX = "Dx"; //$NON-NLS-1$ - - /** - * Dex conversion flag. This is set to true if one of the changed/added/removed - * file is a .class file. Upon visiting all the delta resource, if this - * flag is true, then we know we'll have to make the "classes.dex" file. - */ - private boolean mConvertToDex = false; - - /** - * Package resources flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resource, if - * this flag is true, then we know we'll have to repackage the resources. - */ - private boolean mPackageResources = false; - - /** - * Final package build flag. - */ - private boolean mBuildFinalPackage = false; - - private PrintStream mOutStream = null; - private PrintStream mErrStream = null; - - /** - * Basic Resource Delta Visitor class to check if a referenced project had a change in its - * compiled java files. - */ - private static class ReferencedProjectDeltaVisitor implements IResourceDeltaVisitor { - - private boolean mConvertToDex = false; - private boolean mMakeFinalPackage; - - private IPath mOutputFolder; - private ArrayList<IPath> mSourceFolders; - - private ReferencedProjectDeltaVisitor(IJavaProject javaProject) { - try { - mOutputFolder = javaProject.getOutputLocation(); - mSourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); - } catch (JavaModelException e) { - } finally { - } - } - - /** - * {@inheritDoc} - * @throws CoreException - */ - public boolean visit(IResourceDelta delta) throws CoreException { - // no need to keep looking if we already know we need to convert - // to dex and make the final package. - if (mConvertToDex && mMakeFinalPackage) { - return false; - } - - // get the resource and the path segments. - IResource resource = delta.getResource(); - IPath resourceFullPath = resource.getFullPath(); - - if (mOutputFolder.isPrefixOf(resourceFullPath)) { - int type = resource.getType(); - if (type == IResource.FILE) { - String ext = resource.getFileExtension(); - if (AndroidConstants.EXT_CLASS.equals(ext)) { - mConvertToDex = true; - } - } - return true; - } else { - for (IPath sourceFullPath : mSourceFolders) { - if (sourceFullPath.isPrefixOf(resourceFullPath)) { - int type = resource.getType(); - if (type == IResource.FILE) { - // check if the file is a valid file that would be - // included during the final packaging. - if (checkFileForPackaging((IFile)resource)) { - mMakeFinalPackage = true; - } - - return false; - } else if (type == IResource.FOLDER) { - // if this is a folder, we check if this is a valid folder as well. - // If this is a folder that needs to be ignored, we must return false, - // so that we ignore its content. - return checkFolderForPackaging((IFolder)resource); - } - } - } - } - - return true; - } - - /** - * Returns if one of the .class file was modified. - */ - boolean needDexConvertion() { - return mConvertToDex; - } - - boolean needMakeFinalPackage() { - return mMakeFinalPackage; - } - } - - /** - * {@link IZipEntryFilter} to filter out everything that is not a standard java resources. - * <p/>Used in {@link SignedJarBuilder#writeZip(java.io.InputStream, IZipEntryFilter)} when - * we only want the java resources from external jars. - */ - private final IZipEntryFilter mJavaResourcesFilter = new JavaResourceFilter(); - - public ApkBuilder() { - super(); - } - - // build() returns a list of project from which this project depends for future compilation. - @SuppressWarnings("unchecked") //$NON-NLS-1$ - @Override - protected IProject[] build(int kind, Map args, IProgressMonitor monitor) - throws CoreException { - // get a project object - IProject project = getProject(); - - // get the list of referenced projects. - IProject[] referencedProjects = ProjectHelper.getReferencedProjects(project); - IJavaProject[] referencedJavaProjects = getJavaProjects(referencedProjects); - - // get the output folder, this method returns the path with a trailing - // separator - IJavaProject javaProject = JavaCore.create(project); - IFolder outputFolder = BaseProjectHelper.getOutputFolder(project); - - // now we need to get the classpath list - ArrayList<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject); - - // First thing we do is go through the resource delta to not - // lose it if we have to abort the build for any reason. - ApkDeltaVisitor dv = null; - if (kind == FULL_BUILD) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Start_Full_Apk_Build); - - mPackageResources = true; - mConvertToDex = true; - mBuildFinalPackage = true; - } else { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Start_Inc_Apk_Build); - - // go through the resources and see if something changed. - IResourceDelta delta = getDelta(project); - if (delta == null) { - mPackageResources = true; - mConvertToDex = true; - mBuildFinalPackage = true; - } else { - dv = new ApkDeltaVisitor(this, sourceList, outputFolder); - delta.accept(dv); - - // save the state - mPackageResources |= dv.getPackageResources(); - mConvertToDex |= dv.getConvertToDex(); - mBuildFinalPackage |= dv.getMakeFinalPackage(); - } - - // also go through the delta for all the referenced projects, until we are forced to - // compile anyway - for (int i = 0 ; i < referencedJavaProjects.length && - (mBuildFinalPackage == false || mConvertToDex == false); i++) { - IJavaProject referencedJavaProject = referencedJavaProjects[i]; - delta = getDelta(referencedJavaProject.getProject()); - if (delta != null) { - ReferencedProjectDeltaVisitor refProjectDv = new ReferencedProjectDeltaVisitor( - referencedJavaProject); - delta.accept(refProjectDv); - - // save the state - mConvertToDex |= refProjectDv.needDexConvertion(); - mBuildFinalPackage |= refProjectDv.needMakeFinalPackage(); - } - } - } - - // do some extra check, in case the output files are not present. This - // will force to recreate them. - IResource tmp = null; - - if (mPackageResources == false && outputFolder != null) { - tmp = outputFolder.findMember(AndroidConstants.FN_RESOURCES_AP_); - if (tmp == null || tmp.exists() == false) { - mPackageResources = true; - mBuildFinalPackage = true; - } - } - if (mConvertToDex == false && outputFolder != null) { - tmp = outputFolder.findMember(AndroidConstants.FN_CLASSES_DEX); - if (tmp == null || tmp.exists() == false) { - mConvertToDex = true; - mBuildFinalPackage = true; - } - } - - // get the extra configs for the project. This will give us a list of custom apk - // to build based on a restricted set of resources. - Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project); - - // also check the final file(s)! - String finalPackageName = getFileName(project, null /*config*/); - if (mBuildFinalPackage == false && outputFolder != null) { - tmp = outputFolder.findMember(finalPackageName); - if (tmp == null || (tmp instanceof IFile && - tmp.exists() == false)) { - String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg); - mBuildFinalPackage = true; - } - - if (configs != null) { - Set<Entry<String, String>> entrySet = configs.entrySet(); - - for (Entry<String, String> entry : entrySet) { - String filename = getFileName(project, entry.getKey()); - - tmp = outputFolder.findMember(filename); - if (tmp == null || (tmp instanceof IFile && - tmp.exists() == false)) { - String msg = String.format(Messages.s_Missing_Repackaging, - finalPackageName); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg); - mBuildFinalPackage = true; - break; - } - } - } - } - - // store the build status in the persistent storage - saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , mConvertToDex); - saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources); - saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage); - - // At this point, we can abort the build if we have to, as we have computed - // our resource delta and stored the result. - abortOnBadSetup(project); - - if (dv != null && dv.mXmlError) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Xml_Error); - - // if there was some XML errors, we just return w/o doing - // anything since we've put some markers in the files anyway - return referencedProjects; - } - - if (outputFolder == null) { - // mark project and exit - markProject(AdtConstants.MARKER_ADT, Messages.Failed_To_Get_Output, - IMarker.SEVERITY_ERROR); - return referencedProjects; - } - - // first thing we do is check that the SDK directory has been setup. - String osSdkFolder = AdtPlugin.getOsSdkFolder(); - - if (osSdkFolder.length() == 0) { - // this has already been checked in the precompiler. Therefore, - // while we do have to cancel the build, we don't have to return - // any error or throw anything. - return referencedProjects; - } - - // at this point we know if we need to recreate the temporary apk - // or the dex file, but we don't know if we simply need to recreate them - // because they are missing - - // refresh the output directory first - IContainer ic = outputFolder.getParent(); - if (ic != null) { - ic.refreshLocal(IResource.DEPTH_ONE, monitor); - } - - // we need to test all three, as we may need to make the final package - // but not the intermediary ones. - if (mPackageResources || mConvertToDex || mBuildFinalPackage) { - IPath binLocation = outputFolder.getLocation(); - if (binLocation == null) { - markProject(AdtConstants.MARKER_ADT, Messages.Output_Missing, - IMarker.SEVERITY_ERROR); - return referencedProjects; - } - String osBinPath = binLocation.toOSString(); - - // Remove the old .apk. - // This make sure that if the apk is corrupted, then dx (which would attempt - // to open it), will not fail. - String osFinalPackagePath = osBinPath + File.separator + finalPackageName; - File finalPackage = new File(osFinalPackagePath); - - // if delete failed, this is not really a problem, as the final package generation - // handle already present .apk, and if that one failed as well, the user will be - // notified. - finalPackage.delete(); - - if (configs != null) { - Set<Entry<String, String>> entrySet = configs.entrySet(); - for (Entry<String, String> entry : entrySet) { - String packageFilepath = osBinPath + File.separator + - getFileName(project, entry.getKey()); - - finalPackage = new File(packageFilepath); - finalPackage.delete(); - } - } - - // first we check if we need to package the resources. - if (mPackageResources) { - // need to figure out some path before we can execute aapt; - - // resource to the AndroidManifest.xml file - IResource manifestResource = project .findMember( - AndroidConstants.WS_SEP + AndroidConstants.FN_ANDROID_MANIFEST); - - if (manifestResource == null - || manifestResource.exists() == false) { - // mark project and exit - String msg = String.format(Messages.s_File_Missing, - AndroidConstants.FN_ANDROID_MANIFEST); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return referencedProjects; - } - - // get the resource folder - IFolder resFolder = project.getFolder( - AndroidConstants.WS_RESOURCES); - - // and the assets folder - IFolder assetsFolder = project.getFolder( - AndroidConstants.WS_ASSETS); - - // we need to make sure this one exists. - if (assetsFolder.exists() == false) { - assetsFolder = null; - } - - IPath resLocation = resFolder.getLocation(); - IPath manifestLocation = manifestResource.getLocation(); - - if (resLocation != null && manifestLocation != null) { - String osResPath = resLocation.toOSString(); - String osManifestPath = manifestLocation.toOSString(); - - String osAssetsPath = null; - if (assetsFolder != null) { - osAssetsPath = assetsFolder.getLocation().toOSString(); - } - - // build the default resource package - if (executeAapt(project, osManifestPath, osResPath, - osAssetsPath, osBinPath + File.separator + - AndroidConstants.FN_RESOURCES_AP_, null /*configFilter*/) == false) { - // aapt failed. Whatever files that needed to be marked - // have already been marked. We just return. - return referencedProjects; - } - - // now do the same thing for all the configured resource packages. - if (configs != null) { - Set<Entry<String, String>> entrySet = configs.entrySet(); - for (Entry<String, String> entry : entrySet) { - String outPathFormat = osBinPath + File.separator + - AndroidConstants.FN_RESOURCES_S_AP_; - String outPath = String.format(outPathFormat, entry.getKey()); - if (executeAapt(project, osManifestPath, osResPath, - osAssetsPath, outPath, entry.getValue()) == false) { - // aapt failed. Whatever files that needed to be marked - // have already been marked. We just return. - return referencedProjects; - } - } - } - - // build has been done. reset the state of the builder - mPackageResources = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources); - } - } - - // then we check if we need to package the .class into classes.dex - if (mConvertToDex) { - if (executeDx(javaProject, osBinPath, osBinPath + File.separator + - AndroidConstants.FN_CLASSES_DEX, referencedJavaProjects) == false) { - // dx failed, we return - return referencedProjects; - } - - // build has been done. reset the state of the builder - mConvertToDex = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex); - } - - // now we need to make the final package from the intermediary apk - // and classes.dex. - // This is the default package with all the resources. - - String classesDexPath = osBinPath + File.separator + AndroidConstants.FN_CLASSES_DEX; - if (finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_, - classesDexPath,osFinalPackagePath, javaProject, - referencedJavaProjects) == false) { - return referencedProjects; - } - - // now do the same thing for all the configured resource packages. - if (configs != null) { - String resPathFormat = osBinPath + File.separator + - AndroidConstants.FN_RESOURCES_S_AP_; - - Set<Entry<String, String>> entrySet = configs.entrySet(); - for (Entry<String, String> entry : entrySet) { - // make the filename for the resource package. - String resPath = String.format(resPathFormat, entry.getKey()); - - // make the filename for the apk to generate - String apkOsFilePath = osBinPath + File.separator + - getFileName(project, entry.getKey()); - if (finalPackage(resPath, classesDexPath, apkOsFilePath, javaProject, - referencedJavaProjects) == false) { - return referencedProjects; - } - } - } - - // we are done. - - // get the resource to bin - outputFolder.refreshLocal(IResource.DEPTH_ONE, monitor); - - // build has been done. reset the state of the builder - mBuildFinalPackage = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage); - - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - "Build Success!"); - } - return referencedProjects; - } - - - @Override - protected void startupOnInitialize() { - super.startupOnInitialize(); - - // load the build status. We pass true as the default value to - // force a recompile in case the property was not found - mConvertToDex = loadProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , true); - mPackageResources = loadProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, true); - mBuildFinalPackage = loadProjectBooleanProperty(PROPERTY_BUILD_APK, true); - } - - /** - * Executes aapt. If any error happen, files or the project will be marked. - * @param project The Project - * @param osManifestPath The path to the manifest file - * @param osResPath The path to the res folder - * @param osAssetsPath The path to the assets folder. This can be null. - * @param osOutFilePath The path to the temporary resource file to create. - * @param configFilter The configuration filter for the resources to include - * (used with -c option) - * @return true if success, false otherwise. - */ - private boolean executeAapt(IProject project, String osManifestPath, - String osResPath, String osAssetsPath, String osOutFilePath, String configFilter) { - IAndroidTarget target = Sdk.getCurrent().getTarget(project); - - // Create the command line. - ArrayList<String> commandArray = new ArrayList<String>(); - commandArray.add(target.getPath(IAndroidTarget.AAPT)); - commandArray.add("package"); //$NON-NLS-1$ - commandArray.add("-f");//$NON-NLS-1$ - if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) { - commandArray.add("-v"); //$NON-NLS-1$ - } - if (configFilter != null) { - commandArray.add("-c"); //$NON-NLS-1$ - commandArray.add(configFilter); - } - commandArray.add("-M"); //$NON-NLS-1$ - commandArray.add(osManifestPath); - commandArray.add("-S"); //$NON-NLS-1$ - commandArray.add(osResPath); - if (osAssetsPath != null) { - commandArray.add("-A"); //$NON-NLS-1$ - commandArray.add(osAssetsPath); - } - commandArray.add("-I"); //$NON-NLS-1$ - commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR)); - commandArray.add("-F"); //$NON-NLS-1$ - commandArray.add(osOutFilePath); - - String command[] = commandArray.toArray( - new String[commandArray.size()]); - - if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) { - StringBuilder sb = new StringBuilder(); - for (String c : command) { - sb.append(c); - sb.append(' '); - } - AdtPlugin.printToConsole(project, sb.toString()); - } - - // launch - int execError = 1; - try { - // launch the command line process - Process process = Runtime.getRuntime().exec(command); - - // list to store each line of stderr - ArrayList<String> results = new ArrayList<String>(); - - // get the output and return code from the process - execError = grabProcessOutput(process, results); - - // attempt to parse the error output - boolean parsingError = parseAaptOutput(results, project); - - // if we couldn't parse the output we display it in the console. - if (parsingError) { - if (execError != 0) { - AdtPlugin.printErrorToConsole(project, results.toArray()); - } else { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, project, - results.toArray()); - } - } - - // We need to abort if the exec failed. - if (execError != 0) { - // if the exec failed, and we couldn't parse the error output (and therefore - // not all files that should have been marked, were marked), we put a generic - // marker on the project and abort. - if (parsingError) { - markProject(AdtConstants.MARKER_ADT, Messages.Unparsed_AAPT_Errors, - IMarker.SEVERITY_ERROR); - } - - // abort if exec failed. - return false; - } - } catch (IOException e1) { - String msg = String.format(Messages.AAPT_Exec_Error, command[0]); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } catch (InterruptedException e) { - String msg = String.format(Messages.AAPT_Exec_Error, command[0]); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } - - return true; - } - - /** - * Execute the Dx tool for dalvik code conversion. - * @param javaProject The java project - * @param osBinPath the path to the output folder of the project - * @param osOutFilePath the path of the dex file to create. - * @param referencedJavaProjects the list of referenced projects for this project. - * - * @throws CoreException - */ - private boolean executeDx(IJavaProject javaProject, String osBinPath, String osOutFilePath, - IJavaProject[] referencedJavaProjects) throws CoreException { - IAndroidTarget target = Sdk.getCurrent().getTarget(javaProject.getProject()); - AndroidTargetData targetData = Sdk.getCurrent().getTargetData(target); - if (targetData == null) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - Messages.ApkBuilder_UnableBuild_Dex_Not_loaded)); - } - - // get the dex wrapper - DexWrapper wrapper = targetData.getDexWrapper(); - - if (wrapper == null) { - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - Messages.ApkBuilder_UnableBuild_Dex_Not_loaded)); - } - - // make sure dx use the proper output streams. - // first make sure we actually have the streams available. - if (mOutStream == null) { - IProject project = getProject(); - mOutStream = AdtPlugin.getOutPrintStream(project, DX_PREFIX); - mErrStream = AdtPlugin.getErrPrintStream(project, DX_PREFIX); - } - - try { - // get the list of libraries to include with the source code - String[] libraries = getExternalJars(); - - // get the list of referenced projects output to add - String[] projectOutputs = getProjectOutputs(referencedJavaProjects); - - String[] fileNames = new String[1 + projectOutputs.length + libraries.length]; - - // first this project output - fileNames[0] = osBinPath; - - // then other project output - System.arraycopy(projectOutputs, 0, fileNames, 1, projectOutputs.length); - - // then external jars. - System.arraycopy(libraries, 0, fileNames, 1 + projectOutputs.length, libraries.length); - - int res = wrapper.run(osOutFilePath, fileNames, - AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE, - mOutStream, mErrStream); - - if (res != 0) { - // output error message and marker the project. - String message = String.format(Messages.Dalvik_Error_d, - res); - AdtPlugin.printErrorToConsole(getProject(), message); - markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR); - return false; - } - } catch (Throwable ex) { - String message = ex.getMessage(); - if (message == null) { - message = ex.getClass().getCanonicalName(); - } - message = String.format(Messages.Dalvik_Error_s, message); - AdtPlugin.printErrorToConsole(getProject(), message); - markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR); - if ((ex instanceof NoClassDefFoundError) - || (ex instanceof NoSuchMethodError)) { - AdtPlugin.printErrorToConsole(getProject(), Messages.Incompatible_VM_Warning, - Messages.Requires_1_5_Error); - } - return false; - } - - return true; - } - - /** - * Makes the final package. Package the dex files, the temporary resource file into the final - * package file. - * @param intermediateApk The path to the temporary resource file. - * @param dex The path to the dex file. - * @param output The path to the final package file to create. - * @param javaProject - * @param referencedJavaProjects - * @return true if success, false otherwise. - */ - private boolean finalPackage(String intermediateApk, String dex, String output, - final IJavaProject javaProject, IJavaProject[] referencedJavaProjects) { - FileOutputStream fos = null; - try { - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - String osKeyPath = store.getString(AdtPlugin.PREFS_CUSTOM_DEBUG_KEYSTORE); - if (osKeyPath == null || new File(osKeyPath).exists() == false) { - osKeyPath = DebugKeyProvider.getDefaultKeyStoreOsPath(); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - Messages.ApkBuilder_Using_Default_Key); - } else { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - String.format(Messages.ApkBuilder_Using_s_To_Sign, osKeyPath)); - } - - // TODO: get the store type from somewhere else. - DebugKeyProvider provider = new DebugKeyProvider(osKeyPath, null /* storeType */, - new IKeyGenOutput() { - public void err(String message) { - AdtPlugin.printErrorToConsole(javaProject.getProject(), - Messages.ApkBuilder_Signing_Key_Creation_s + message); - } - - public void out(String message) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, - javaProject.getProject(), - Messages.ApkBuilder_Signing_Key_Creation_s + message); - } - }); - PrivateKey key = provider.getDebugKey(); - X509Certificate certificate = (X509Certificate)provider.getCertificate(); - - if (key == null) { - String msg = String.format(Messages.Final_Archive_Error_s, - Messages.ApkBuilder_Unable_To_Gey_Key); - AdtPlugin.printErrorToConsole(javaProject.getProject(), msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } - - // compare the certificate expiration date - if (certificate != null && certificate.getNotAfter().compareTo(new Date()) < 0) { - // TODO, regenerate a new one. - String msg = String.format(Messages.Final_Archive_Error_s, - String.format(Messages.ApkBuilder_Certificate_Expired_on_s, - DateFormat.getInstance().format(certificate.getNotAfter()))); - AdtPlugin.printErrorToConsole(javaProject.getProject(), msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } - - // create the jar builder. - fos = new FileOutputStream(output); - SignedJarBuilder builder = new SignedJarBuilder(fos, key, certificate); - - // add the intermediate file containing the compiled resources. - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - String.format(Messages.ApkBuilder_Packaging_s, intermediateApk)); - FileInputStream fis = new FileInputStream(intermediateApk); - try { - builder.writeZip(fis, null /* filter */); - } finally { - fis.close(); - } - - // Now we add the new file to the zip archive for the classes.dex file. - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - String.format(Messages.ApkBuilder_Packaging_s, AndroidConstants.FN_CLASSES_DEX)); - File entryFile = new File(dex); - builder.writeFile(entryFile, AndroidConstants.FN_CLASSES_DEX); - - // Now we write the standard resources from the project and the referenced projects. - writeStandardResources(builder, javaProject, referencedJavaProjects); - - // Now we write the standard resources from the external libraries - for (String libraryOsPath : getExternalJars()) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - String.format(Messages.ApkBuilder_Packaging_s, libraryOsPath)); - try { - fis = new FileInputStream(libraryOsPath); - builder.writeZip(fis, mJavaResourcesFilter); - } finally { - fis.close(); - } - } - - // now write the native libraries. - // First look if the lib folder is there. - IResource libFolder = javaProject.getProject().findMember(SdkConstants.FD_NATIVE_LIBS); - if (libFolder != null && libFolder.exists() && - libFolder.getType() == IResource.FOLDER) { - // look inside and put .so in lib/* by keeping the relative folder path. - writeNativeLibraries(libFolder.getFullPath().segmentCount(), builder, libFolder); - } - - // close the jar file and write the manifest and sign it. - builder.close(); - } catch (GeneralSecurityException e1) { - // mark project and return - String msg = String.format(Messages.Final_Archive_Error_s, e1.getMessage()); - AdtPlugin.printErrorToConsole(javaProject.getProject(), msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } catch (IOException e1) { - // mark project and return - String msg = String.format(Messages.Final_Archive_Error_s, e1.getMessage()); - AdtPlugin.printErrorToConsole(javaProject.getProject(), msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } catch (KeytoolException e) { - String eMessage = e.getMessage(); - - // mark the project with the standard message - String msg = String.format(Messages.Final_Archive_Error_s, eMessage); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // output more info in the console - AdtPlugin.printErrorToConsole(javaProject.getProject(), - msg, - String.format(Messages.ApkBuilder_JAVA_HOME_is_s, e.getJavaHome()), - Messages.ApkBuilder_Update_or_Execute_manually_s, - e.getCommandLine()); - } catch (AndroidLocationException e) { - String eMessage = e.getMessage(); - - // mark the project with the standard message - String msg = String.format(Messages.Final_Archive_Error_s, eMessage); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // and also output it in the console - AdtPlugin.printErrorToConsole(javaProject.getProject(), msg); - } catch (CoreException e) { - // mark project and return - String msg = String.format(Messages.Final_Archive_Error_s, e.getMessage()); - AdtPlugin.printErrorToConsole(javaProject.getProject(), msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } finally { - if (fos != null) { - try { - fos.close(); - } catch (IOException e) { - // pass. - } - } - } - - return true; - } - - /** - * Writes native libraries into a {@link SignedJarBuilder}. - * <p/>This recursively go through folder and writes .so files. - * The path in the archive is based on the root folder containing the libraries in the project. - * Its segment count is passed to the method to compute the resources path relative to the root - * folder. - * Native libraries in the archive must be in a "lib" folder. Everything in the project native - * lib folder directly goes in this "lib" folder in the archive. - * - * - * @param rootSegmentCount The number of segment of the path of the folder containing the - * libraries. This is used to compute the path in the archive. - * @param jarBuilder the {@link SignedJarBuilder} used to create the archive. - * @param resource the IResource to write. - * @throws CoreException - * @throws IOException - */ - private void writeNativeLibraries(int rootSegmentCount, SignedJarBuilder jarBuilder, - IResource resource) throws CoreException, IOException { - if (resource.getType() == IResource.FILE) { - IPath path = resource.getFullPath(); - - // check the extension. - if (path.getFileExtension().equalsIgnoreCase(AndroidConstants.EXT_NATIVE_LIB)) { - // remove the first segment to build the path inside the archive. - path = path.removeFirstSegments(rootSegmentCount); - - // add it to the archive. - IPath apkPath = new Path(SdkConstants.FD_APK_NATIVE_LIBS); - apkPath = apkPath.append(path); - - // writes the file in the apk. - jarBuilder.writeFile(resource.getLocation().toFile(), apkPath.toString()); - } - } else if (resource.getType() == IResource.FOLDER) { - IResource[] members = ((IFolder)resource).members(); - for (IResource member : members) { - writeNativeLibraries(rootSegmentCount, jarBuilder, member); - } - } - } - - /** - * Writes the standard resources of a project and its referenced projects - * into a {@link SignedJarBuilder}. - * Standard resources are non java/aidl files placed in the java package folders. - * @param jarBuilder the {@link SignedJarBuilder}. - * @param javaProject the javaProject object. - * @param referencedJavaProjects the java projects that this project references. - * @throws IOException - */ - private void writeStandardResources(SignedJarBuilder jarBuilder, IJavaProject javaProject, - IJavaProject[] referencedJavaProjects) throws IOException { - IWorkspace ws = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot wsRoot = ws.getRoot(); - - // create a list of path already put into the archive, in order to detect conflict - ArrayList<String> list = new ArrayList<String>(); - - writeStandardProjectResources(jarBuilder, javaProject, wsRoot, list); - - for (IJavaProject referencedJavaProject : referencedJavaProjects) { - writeStandardProjectResources(jarBuilder, referencedJavaProject, wsRoot, list); - } - } - - /** - * Writes the standard resources of a {@link IJavaProject} into a {@link SignedJarBuilder}. - * Standard resources are non java/aidl files placed in the java package folders. - * @param jarBuilder the {@link SignedJarBuilder}. - * @param javaProject the javaProject object. - * @param wsRoot the {@link IWorkspaceRoot}. - * @param list a list of files already added to the archive, to detect conflicts. - * @throws IOException - */ - private void writeStandardProjectResources(SignedJarBuilder jarBuilder, - IJavaProject javaProject, IWorkspaceRoot wsRoot, ArrayList<String> list) - throws IOException { - // get the source pathes - ArrayList<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject); - - // loop on them and then recursively go through the content looking for matching files. - for (IPath sourcePath : sourceFolders) { - IResource sourceResource = wsRoot.findMember(sourcePath); - if (sourceResource != null && sourceResource.getType() == IResource.FOLDER) { - writeStandardSourceFolderResources(jarBuilder, sourcePath, (IFolder)sourceResource, - list); - } - } - } - - /** - * Recursively writes the standard resources of a source folder into a {@link SignedJarBuilder}. - * Standard resources are non java/aidl files placed in the java package folders. - * @param jarBuilder the {@link SignedJarBuilder}. - * @param sourceFolder the {@link IPath} of the source folder. - * @param currentFolder The current folder we're recursively processing. - * @param list a list of files already added to the archive, to detect conflicts. - * @throws IOException - */ - private void writeStandardSourceFolderResources(SignedJarBuilder jarBuilder, IPath sourceFolder, - IFolder currentFolder, ArrayList<String> list) throws IOException { - try { - IResource[] members = currentFolder.members(); - - for (IResource member : members) { - int type = member.getType(); - if (type == IResource.FILE && member.exists()) { - if (checkFileForPackaging((IFile)member)) { - // this files must be added to the archive. - IPath fullPath = member.getFullPath(); - - // We need to create its path inside the archive. - // This path is relative to the source folder. - IPath relativePath = fullPath.removeFirstSegments( - sourceFolder.segmentCount()); - String zipPath = relativePath.toString(); - - // lets check it's not already in the list of path added to the archive - if (list.indexOf(zipPath) != -1) { - AdtPlugin.printErrorToConsole(getProject(), - String.format( - Messages.ApkBuilder_s_Conflict_with_file_s, - fullPath, zipPath)); - } else { - // get the File object - File entryFile = member.getLocation().toFile(); - - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - String.format(Messages.ApkBuilder_Packaging_s_into_s, fullPath, zipPath)); - - // write it in the zip archive - jarBuilder.writeFile(entryFile, zipPath); - - // and add it to the list of entries - list.add(zipPath); - } - } - } else if (type == IResource.FOLDER) { - if (checkFolderForPackaging((IFolder)member)) { - writeStandardSourceFolderResources(jarBuilder, sourceFolder, - (IFolder)member, list); - } - } - } - } catch (CoreException e) { - // if we can't get the members of the folder, we just don't do anything. - } - } - - /** - * Returns the list of the output folders for the specified {@link IJavaProject} objects. - * @param referencedJavaProjects the java projects. - * @return an array, always. Can be empty. - * @throws CoreException - */ - private String[] getProjectOutputs(IJavaProject[] referencedJavaProjects) throws CoreException { - ArrayList<String> list = new ArrayList<String>(); - - IWorkspace ws = ResourcesPlugin.getWorkspace(); - IWorkspaceRoot wsRoot = ws.getRoot(); - - for (IJavaProject javaProject : referencedJavaProjects) { - // get the output folder - IPath path = null; - try { - path = javaProject.getOutputLocation(); - } catch (JavaModelException e) { - continue; - } - - IResource outputResource = wsRoot.findMember(path); - if (outputResource != null && outputResource.getType() == IResource.FOLDER) { - String outputOsPath = outputResource.getLocation().toOSString(); - - list.add(outputOsPath); - } - } - - return list.toArray(new String[list.size()]); - } - - /** - * Returns an array of {@link IJavaProject} matching the provided {@link IProject} objects. - * @param projects the IProject objects. - * @return an array, always. Can be empty. - * @throws CoreException - */ - private IJavaProject[] getJavaProjects(IProject[] projects) throws CoreException { - ArrayList<IJavaProject> list = new ArrayList<IJavaProject>(); - - for (IProject p : projects) { - if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) { - - list.add(JavaCore.create(p)); - } - } - - return list.toArray(new IJavaProject[list.size()]); - } - - /** - * Returns the apk filename for the given project - * @param project The project. - * @param config An optional config name. Can be null. - */ - private static String getFileName(IProject project, String config) { - if (config != null) { - return project.getName() + "-" + config + AndroidConstants.DOT_ANDROID_PACKAGE; //$NON-NLS-1$ - } - - return project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE; - } - - /** - * Checks a {@link IFile} to make sure it should be packaged as standard resources. - * @param file the IFile representing the file. - * @return true if the file should be packaged as standard java resources. - */ - static boolean checkFileForPackaging(IFile file) { - String name = file.getName(); - - String ext = file.getFileExtension(); - return JavaResourceFilter.checkFileForPackaging(name, ext); - } - - /** - * Checks whether an {@link IFolder} and its content is valid for packaging into the .apk as - * standard Java resource. - * @param folder the {@link IFolder} to check. - */ - static boolean checkFolderForPackaging(IFolder folder) { - String name = folder.getName(); - return JavaResourceFilter.checkFolderForPackaging(name); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java deleted file mode 100644 index 5d6793a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2007 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.build; - -import com.android.ide.eclipse.adt.build.BaseBuilder.BaseDeltaVisitor; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; - -import java.util.ArrayList; - -/** - * Delta resource visitor looking for changes that will trigger a new packaging of an Android - * application. - * <p/> - * This looks for the following changes: - * <ul> - * <li>Any change to the AndroidManifest.xml file</li> - * <li>Any change inside the assets/ folder</li> - * <li>Any file change inside the res/ folder</li> - * <li>Any .class file change inside the output folder</li> - * <li>Any change to the classes.dex inside the output folder</li> - * <li>Any change to the packaged resources file inside the output folder</li> - * <li>Any change to a non java/aidl file inside the source folders</li> - * <li>Any change to .so file inside the lib (native library) folder</li> - * </ul> - */ -public class ApkDeltaVisitor extends BaseDeltaVisitor - implements IResourceDeltaVisitor { - - /** - * compile flag. This is set to true if one of the changed/added/removed - * file is a .class file. Upon visiting all the delta resources, if this - * flag is true, then we know we'll have to make the "classes.dex" file. - */ - private boolean mConvertToDex = false; - - /** - * compile flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resources, if - * this flag is true, then we know we'll have to make the intermediate - * apk file. - */ - private boolean mPackageResources = false; - - /** - * Final package flag. This is set to true if one of the changed/added/removed - * file is a non java file (or aidl) in the resource folder. Upon visiting all the - * delta resources, if this flag is true, then we know we'll have to make the final - * package. - */ - private boolean mMakeFinalPackage = false; - - /** List of source folders. */ - private ArrayList<IPath> mSourceFolders; - - private IPath mOutputPath; - - private IPath mAssetPath; - - private IPath mResPath; - - private IPath mLibFolder; - - /** - * Builds the object with a specified output folder. - * @param builder the xml builder using this object to visit the - * resource delta. - * @param sourceFolders the list of source folders for the project, relative to the workspace. - * @param outputfolder the output folder of the project. - */ - public ApkDeltaVisitor(BaseBuilder builder, ArrayList<IPath> sourceFolders, - IFolder outputfolder) { - super(builder); - mSourceFolders = sourceFolders; - - if (outputfolder != null) { - mOutputPath = outputfolder.getFullPath(); - } - - IResource assetFolder = builder.getProject().findMember(SdkConstants.FD_ASSETS); - if (assetFolder != null) { - mAssetPath = assetFolder.getFullPath(); - } - - IResource resFolder = builder.getProject().findMember(SdkConstants.FD_RESOURCES); - if (resFolder != null) { - mResPath = resFolder.getFullPath(); - } - - IResource libFolder = builder.getProject().findMember(SdkConstants.FD_NATIVE_LIBS); - if (libFolder != null) { - mLibFolder = libFolder.getFullPath(); - } - } - - public boolean getConvertToDex() { - return mConvertToDex; - } - - public boolean getPackageResources() { - return mPackageResources; - } - - public boolean getMakeFinalPackage() { - return mMakeFinalPackage; - } - - /** - * {@inheritDoc} - * @throws CoreException - * - * @see org.eclipse.core.resources.IResourceDeltaVisitor - * #visit(org.eclipse.core.resources.IResourceDelta) - */ - public boolean visit(IResourceDelta delta) throws CoreException { - // if all flags are true, we can stop going through the resource delta. - if (mConvertToDex && mPackageResources && mMakeFinalPackage) { - return false; - } - - // we are only going to look for changes in res/, src/ and in - // AndroidManifest.xml since the delta visitor goes through the main - // folder before its childre we can check when the path segment - // count is 2 (format will be /$Project/folder) and make sure we are - // processing res/, src/ or AndroidManifest.xml - IResource resource = delta.getResource(); - IPath path = resource.getFullPath(); - String[] pathSegments = path.segments(); - int type = resource.getType(); - - // since the delta visitor also visits the root we return true if - // segments.length = 1 - if (pathSegments.length == 1) { - return true; - } - - // check the manifest. - if (pathSegments.length == 2 && - AndroidConstants.FN_ANDROID_MANIFEST.equalsIgnoreCase(pathSegments[1])) { - // if the manifest changed we have to repackage the - // resources. - mPackageResources = true; - mMakeFinalPackage = true; - - // we don't want to go to the children, not like they are - // any for this resource anyway. - return false; - } - - // check the other folders. - if (mOutputPath != null && mOutputPath.isPrefixOf(path)) { - // a resource changed inside the output folder. - if (type == IResource.FILE) { - // just check this is a .class file. Any modification will - // trigger a change in the classes.dex file - String ext = resource.getFileExtension(); - if (AndroidConstants.EXT_CLASS.equalsIgnoreCase(ext)) { - mConvertToDex = true; - mMakeFinalPackage = true; - - // no need to check the children, as we are in a package - // and there can only be subpackage children containing - // only .class files - return false; - } - - // check for a few files directly in the output folder and force - // rebuild if they have been deleted. - if (delta.getKind() == IResourceDelta.REMOVED) { - IPath parentPath = path.removeLastSegments(1); - if (mOutputPath.equals(parentPath)) { - String resourceName = resource.getName(); - // check if classes.dex was removed - if (resourceName.equalsIgnoreCase(AndroidConstants.FN_CLASSES_DEX)) { - mConvertToDex = true; - mMakeFinalPackage = true; - } else if (resourceName.equalsIgnoreCase( - AndroidConstants.FN_RESOURCES_AP_) || - AndroidConstants.PATTERN_RESOURCES_S_AP_.matcher( - resourceName).matches()) { - // or if the default resources.ap_ or a configured version - // (resources-###.ap_) was removed. - mPackageResources = true; - mMakeFinalPackage = true; - } - } - } - } - - // if this is a folder, we only go visit it if we don't already know - // that we need to convert to dex already. - return mConvertToDex == false; - } else if (mResPath != null && mResPath.isPrefixOf(path)) { - // in the res folder we are looking for any file modification - // (we don't care about folder being added/removed, only content - // is important) - if (type == IResource.FILE) { - mPackageResources = true; - mMakeFinalPackage = true; - return false; - } - - // for folders, return true only if we don't already know we have to - // package the resources. - return mPackageResources == false; - } else if (mAssetPath != null && mAssetPath.isPrefixOf(path)) { - // this is the assets folder that was modified. - // we don't care what content was changed. All we care - // about is that something changed inside. No need to visit - // the children even. - mPackageResources = true; - mMakeFinalPackage = true; - return false; - } else if (mLibFolder != null && mLibFolder.isPrefixOf(path)) { - // inside the native library folder. Test if the changed resource is a .so file. - if (type == IResource.FILE && - path.getFileExtension().equalsIgnoreCase(AndroidConstants.EXT_NATIVE_LIB)) { - mMakeFinalPackage = true; - return false; // return false for file. - } - - // for folders, return true only if we don't already know we have to make the - // final package. - return mMakeFinalPackage == false; - } else { - // we are in a folder that is neither the resource folders, nor the output. - // check against all the source folders, unless we already know we need to do - // the final package. - // This could be a source folder or a folder leading to a source folder. - // However we only check this if we don't already know that we need to build the - // package anyway - if (mMakeFinalPackage == false) { - for (IPath sourcePath : mSourceFolders) { - if (sourcePath.isPrefixOf(path)) { - // In the source folders, we are looking for any kind of - // modification related to file that are not java files. - // Also excluded are aidl files, and package.html files - if (type == IResource.FOLDER) { - // always visit the subfolders, unless the folder is not to be included - return ApkBuilder.checkFolderForPackaging((IFolder)resource); - } else if (type == IResource.FILE) { - if (ApkBuilder.checkFileForPackaging((IFile)resource)) { - mMakeFinalPackage = true; - } - - return false; - } - - } - } - } - } - - // if the folder is not inside one of the folders we are interested in (res, assets, output, - // source folders), it could be a folder leading to them, so we return true. - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java deleted file mode 100644 index 6b0810a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Copyright (C) 2007 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.build; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.LoadStatus; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.common.project.XmlErrorHandler; -import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.xml.sax.SAXException; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Base builder for XML files. This class allows for basic XML parsing with - * error checking and marking the files for errors/warnings. - */ -abstract class BaseBuilder extends IncrementalProjectBuilder { - - // TODO: rename the pattern to something that makes sense + javadoc comments. - - /** - * Single line aapt warning for skipping files.<br> - * " (skipping hidden file '<file path>'" - */ - private final static Pattern sPattern0Line1 = Pattern.compile( - "^\\s+\\(skipping hidden file\\s'(.*)'\\)$"); //$NON-NLS-1$ - - /** - * First line of dual line aapt error.<br> - * "ERROR at line <line>: <error>"<br> - * " (Occurred while parsing <path>)" - */ - private final static Pattern sPattern1Line1 = Pattern.compile( - "^ERROR\\s+at\\s+line\\s+(\\d+):\\s+(.*)$"); //$NON-NLS-1$ - /** - * Second line of dual line aapt error.<br> - * "ERROR at line <line>: <error>"<br> - * " (Occurred while parsing <path>)"<br> - * @see #sPattern1Line1 - */ - private final static Pattern sPattern1Line2 = Pattern.compile( - "^\\s+\\(Occurred while parsing\\s+(.*)\\)$"); //$NON-NLS-1$ - /** - * First line of dual line aapt error.<br> - * "ERROR: <error>"<br> - * "Defined at file <path> line <line>" - */ - private final static Pattern sPattern2Line1 = Pattern.compile( - "^ERROR:\\s+(.+)$"); //$NON-NLS-1$ - /** - * Second line of dual line aapt error.<br> - * "ERROR: <error>"<br> - * "Defined at file <path> line <line>"<br> - * @see #sPattern2Line1 - */ - private final static Pattern sPattern2Line2 = Pattern.compile( - "Defined\\s+at\\s+file\\s+(.+)\\s+line\\s+(\\d+)"); //$NON-NLS-1$ - /** - * Single line aapt error<br> - * "<path> line <line>: <error>" - */ - private final static Pattern sPattern3Line1 = Pattern.compile( - "^(.+)\\sline\\s(\\d+):\\s(.+)$"); //$NON-NLS-1$ - /** - * First line of dual line aapt error.<br> - * "ERROR parsing XML file <path>"<br> - * "<error> at line <line>" - */ - private final static Pattern sPattern4Line1 = Pattern.compile( - "^Error\\s+parsing\\s+XML\\s+file\\s(.+)$"); //$NON-NLS-1$ - /** - * Second line of dual line aapt error.<br> - * "ERROR parsing XML file <path>"<br> - * "<error> at line <line>"<br> - * @see #sPattern4Line1 - */ - private final static Pattern sPattern4Line2 = Pattern.compile( - "^(.+)\\s+at\\s+line\\s+(\\d+)$"); //$NON-NLS-1$ - - /** - * Single line aapt warning<br> - * "<path>:<line>: <error>" - */ - private final static Pattern sPattern5Line1 = Pattern.compile( - "^(.+?):(\\d+):\\s+WARNING:(.+)$"); //$NON-NLS-1$ - - /** - * Single line aapt error<br> - * "<path>:<line>: <error>" - */ - private final static Pattern sPattern6Line1 = Pattern.compile( - "^(.+?):(\\d+):\\s+(.+)$"); //$NON-NLS-1$ - - /** - * 4 line aapt error<br> - * "ERROR: 9-path image <path> malformed"<br> - * Line 2 and 3 are taken as-is while line 4 is ignored (it repeats with<br> - * 'ERROR: failure processing <path>) - */ - private final static Pattern sPattern7Line1 = Pattern.compile( - "^ERROR:\\s+9-patch\\s+image\\s+(.+)\\s+malformed\\.$"); //$NON-NLS-1$ - - private final static Pattern sPattern8Line1 = Pattern.compile( - "^(invalid resource directory name): (.*)$"); //$NON-NLS-1$ - - /** SAX Parser factory. */ - private SAXParserFactory mParserFactory; - - /** - * Base Resource Delta Visitor to handle XML error - */ - protected static class BaseDeltaVisitor implements XmlErrorListener { - - /** The Xml builder used to validate XML correctness. */ - protected BaseBuilder mBuilder; - - /** - * XML error flag. if true, we keep parsing the ResourceDelta but the - * compilation will not happen (we're putting markers) - */ - public boolean mXmlError = false; - - public BaseDeltaVisitor(BaseBuilder builder) { - mBuilder = builder; - } - - /** - * Finds a matching Source folder for the current path. This checkds if the current path - * leads to, or is a source folder. - * @param sourceFolders The list of source folders - * @param pathSegments The segments of the current path - * @return The segments of the source folder, or null if no match was found - */ - protected static String[] findMatchingSourceFolder(ArrayList<IPath> sourceFolders, - String[] pathSegments) { - - for (IPath p : sourceFolders) { - // check if we are inside one of those source class path - - // get the segments - String[] srcSegments = p.segments(); - - // compare segments. We want the path of the resource - // we're visiting to be - boolean valid = true; - int segmentCount = pathSegments.length; - - for (int i = 0 ; i < segmentCount; i++) { - String s1 = pathSegments[i]; - String s2 = srcSegments[i]; - - if (s1.equalsIgnoreCase(s2) == false) { - valid = false; - break; - } - } - - if (valid) { - // this folder, or one of this children is a source - // folder! - // we return its segments - return srcSegments; - } - } - - return null; - } - - /** - * Sent when an XML error is detected. - * @see XmlErrorListener - */ - public void errorFound() { - mXmlError = true; - } - } - - public BaseBuilder() { - super(); - mParserFactory = SAXParserFactory.newInstance(); - - // FIXME when the compiled XML support for namespace is in, set this to true. - mParserFactory.setNamespaceAware(false); - } - - /** - * Checks an Xml file for validity. Errors/warnings will be marked on the - * file - * @param resource the resource to check - * @param visitor a valid resource delta visitor - */ - protected final void checkXML(IResource resource, BaseDeltaVisitor visitor) { - - // first make sure this is an xml file - if (resource instanceof IFile) { - IFile file = (IFile)resource; - - // remove previous markers - removeMarkersFromFile(file, AndroidConstants.MARKER_XML); - - // create the error handler - XmlErrorHandler reporter = new XmlErrorHandler(file, visitor); - try { - // parse - getParser().parse(file.getContents(), reporter); - } catch (Exception e1) { - } - } - } - - /** - * Returns the SAXParserFactory, instantiating it first if it's not already - * created. - * @return the SAXParserFactory object - * @throws ParserConfigurationException - * @throws SAXException - */ - protected final SAXParser getParser() throws ParserConfigurationException, - SAXException { - return mParserFactory.newSAXParser(); - } - - /** - * Adds a marker to the current project. - * - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param severity the severity of the marker. - */ - protected final void markProject(String markerId, String message, int severity) { - BaseProjectHelper.addMarker(getProject(), markerId, message, severity); - } - - - /** - * Removes markers from a file. - * @param file The file from which to delete the markers. - * @param markerId The id of the markers to remove. If null, all marker of - * type <code>IMarker.PROBLEM</code> will be removed. - */ - protected final void removeMarkersFromFile(IFile file, String markerId) { - try { - if (file.exists()) { - file.deleteMarkers(markerId, true, IResource.DEPTH_ZERO); - } - } catch (CoreException ce) { - String msg = String.format(Messages.Marker_Delete_Error, markerId, file.toString()); - AdtPlugin.printErrorToConsole(getProject(), msg); - } - } - - /** - * Removes markers from a container and its children. - * @param folder The container from which to delete the markers. - * @param markerId The id of the markers to remove. If null, all marker of - * type <code>IMarker.PROBLEM</code> will be removed. - */ - protected final void removeMarkersFromContainer(IContainer folder, String markerId) { - try { - if (folder.exists()) { - folder.deleteMarkers(markerId, true, IResource.DEPTH_INFINITE); - } - } catch (CoreException ce) { - String msg = String.format(Messages.Marker_Delete_Error, markerId, folder.toString()); - AdtPlugin.printErrorToConsole(getProject(), msg); - } - } - - /** - * Removes markers from a project and its children. - * @param project The project from which to delete the markers - * @param markerId The id of the markers to remove. If null, all marker of - * type <code>IMarker.PROBLEM</code> will be removed. - */ - protected final static void removeMarkersFromProject(IProject project, - String markerId) { - try { - if (project.exists()) { - project.deleteMarkers(markerId, true, IResource.DEPTH_INFINITE); - } - } catch (CoreException ce) { - String msg = String.format(Messages.Marker_Delete_Error, markerId, project.getName()); - AdtPlugin.printErrorToConsole(project, msg); - } - } - - /** - * Get the stderr output of a process and return when the process is done. - * @param process The process to get the ouput from - * @param results The array to store the stderr output - * @return the process return code. - * @throws InterruptedException - */ - protected final int grabProcessOutput(final Process process, - final ArrayList<String> results) - throws InterruptedException { - // Due to the limited buffer size on windows for the standard io (stderr, stdout), we - // *need* to read both stdout and stderr all the time. If we don't and a process output - // a large amount, this could deadlock the process. - - // read the lines as they come. if null is returned, it's - // because the process finished - new Thread("") { //$NON-NLS-1$ - @Override - public void run() { - // create a buffer to read the stderr output - InputStreamReader is = new InputStreamReader(process.getErrorStream()); - BufferedReader errReader = new BufferedReader(is); - - try { - while (true) { - String line = errReader.readLine(); - if (line != null) { - results.add(line); - } else { - break; - } - } - } catch (IOException e) { - // do nothing. - } - } - }.start(); - - new Thread("") { //$NON-NLS-1$ - @Override - public void run() { - InputStreamReader is = new InputStreamReader(process.getInputStream()); - BufferedReader outReader = new BufferedReader(is); - - IProject project = getProject(); - - try { - while (true) { - String line = outReader.readLine(); - if (line != null) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, - project, line); - } else { - break; - } - } - } catch (IOException e) { - // do nothing. - } - } - - }.start(); - - // get the return code from the process - return process.waitFor(); - } - - /** - * Parse the output of aapt and mark the incorrect file with error markers - * - * @param results the output of aapt - * @param project the project containing the file to mark - * @return true if the parsing failed, false if success. - */ - protected final boolean parseAaptOutput(ArrayList<String> results, - IProject project) { - // nothing to parse? just return false; - if (results.size() == 0) { - return false; - } - - // get the root of the project so that we can make IFile from full - // file path - String osRoot = project.getLocation().toOSString(); - - Matcher m; - - for (int i = 0; i < results.size(); i++) { - String p = results.get(i); - - m = sPattern0Line1.matcher(p); - if (m.matches()) { - // we ignore those (as this is an ignore message from aapt) - continue; - } - - m = sPattern1Line1.matcher(p); - if (m.matches()) { - String lineStr = m.group(1); - String msg = m.group(2); - - // get the matcher for the next line. - m = getNextLineMatcher(results, ++i, sPattern1Line2); - if (m == null) { - return true; - } - - String location = m.group(1); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, - project, IMarker.SEVERITY_ERROR) == false) { - return true; - } - continue; - } - - // this needs to be tested before Pattern2 since they both start with 'ERROR:' - m = sPattern7Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String msg = p; // default msg is the line in case we don't find anything else - - if (++i < results.size()) { - msg = results.get(i).trim(); - if (++i < results.size()) { - msg = msg + " - " + results.get(i).trim(); //$NON-NLS-1$ - - // skip the next line - i++; - } - } - - // display the error - if (checkAndMark(location, null, msg, osRoot, project, - IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern2Line1.matcher(p); - if (m.matches()) { - // get the msg - String msg = m.group(1); - - // get the matcher for the next line. - m = getNextLineMatcher(results, ++i, sPattern2Line2); - if (m == null) { - return true; - } - - String location = m.group(1); - String lineStr = m.group(2); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, - project, IMarker.SEVERITY_ERROR) == false) { - return true; - } - continue; - } - - m = sPattern3Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String lineStr = m.group(2); - String msg = m.group(3); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, - project, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern4Line1.matcher(p); - if (m.matches()) { - // get the filename. - String location = m.group(1); - - // get the matcher for the next line. - m = getNextLineMatcher(results, ++i, sPattern4Line2); - if (m == null) { - return true; - } - - String msg = m.group(1); - String lineStr = m.group(2); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, - project, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern5Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String lineStr = m.group(2); - String msg = m.group(3); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, - project,IMarker.SEVERITY_WARNING) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern6Line1.matcher(p); - if (m.matches()) { - String location = m.group(1); - String lineStr = m.group(2); - String msg = m.group(3); - - // check the values and attempt to mark the file. - if (checkAndMark(location, lineStr, msg, osRoot, - project, IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - m = sPattern8Line1.matcher(p); - if (m.matches()) { - String location = m.group(2); - String msg = m.group(1); - - // check the values and attempt to mark the file. - if (checkAndMark(location, null, msg, osRoot, project, - IMarker.SEVERITY_ERROR) == false) { - return true; - } - - // success, go to the next line - continue; - } - - // invalid line format, flag as error, and bail - return true; - } - - return false; - } - - - - /** - * Saves a String property into the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - protected boolean saveProjectStringProperty(String propertyName, String value) { - IProject project = getProject(); - return ProjectHelper.saveStringProperty(project, propertyName, value); - } - - - /** - * Loads a String property from the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @return the property value or null if it was not found. - */ - protected String loadProjectStringProperty(String propertyName) { - IProject project = getProject(); - return ProjectHelper.loadStringProperty(project, propertyName); - } - - /** - * Saves a property into the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - protected boolean saveProjectBooleanProperty(String propertyName, boolean value) { - IProject project = getProject(); - return ProjectHelper.saveStringProperty(project, propertyName, Boolean.toString(value)); - } - - /** - * Loads a boolean property from the persistent storage of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param defaultValue The default value to return if the property was not found. - * @return the property value or the default value if the property was not found. - */ - protected boolean loadProjectBooleanProperty(String propertyName, boolean defaultValue) { - IProject project = getProject(); - return ProjectHelper.loadBooleanProperty(project, propertyName, defaultValue); - } - - /** - * Saves the path of a resource into the persistent storate of the project. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param resource the resource which path is saved. - * @return true if the save succeeded - */ - protected boolean saveProjectResourceProperty(String propertyName, IResource resource) { - return ProjectHelper.saveResourceProperty(getProject(), propertyName, resource); - } - - /** - * Loads the path of a resource from the persistent storage of the project, and returns the - * corresponding IResource object. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @return The corresponding IResource object (or children interface) or null - */ - protected IResource loadProjectResourceProperty(String propertyName) { - IProject project = getProject(); - return ProjectHelper.loadResourceProperty(project, propertyName); - } - - /** - * Check if the parameters gotten from the error output are valid, and mark - * the file with an AAPT marker. - * @param location - * @param lineStr - * @param message - * @param root The root directory of the project, in OS specific format. - * @param project - * @param severity The severity of the marker to put (IMarker.SEVERITY_*) - * @return true if the parameters were valid and the file was marked - * sucessfully. - * - * @see IMarker - */ - private final boolean checkAndMark(String location, String lineStr, - String message, String root, IProject project, int severity) { - // check this is in fact a file - File f = new File(location); - if (f.exists() == false) { - return false; - } - - // get the line number - int line = -1; // default value for error with no line. - - if (lineStr != null) { - try { - line = Integer.parseInt(lineStr); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid - // file number. Parsing failed and we return true - return false; - } - } - - // add the marker - IResource f2 = getResourceFromFullPath(location, root, project); - if (f2 == null) { - return false; - } - - // check if there's a similar marker already, since aapt is launched twice - boolean markerAlreadyExists = false; - try { - IMarker[] markers = f2.findMarkers(AndroidConstants.MARKER_AAPT, true, - IResource.DEPTH_ZERO); - - for (IMarker marker : markers) { - int tmpLine = marker.getAttribute(IMarker.LINE_NUMBER, -1); - if (tmpLine != line) { - break; - } - - int tmpSeverity = marker.getAttribute(IMarker.SEVERITY, -1); - if (tmpSeverity != severity) { - break; - } - - String tmpMsg = marker.getAttribute(IMarker.MESSAGE, null); - if (tmpMsg == null || tmpMsg.equals(message) == false) { - break; - } - - // if we're here, all the marker attributes are equals, we found it - // and exit - markerAlreadyExists = true; - break; - } - - } catch (CoreException e) { - // if we couldn't get the markers, then we just mark the file again - // (since markerAlreadyExists is initialized to false, we do nothing) - } - - if (markerAlreadyExists == false) { - if (line != -1) { - BaseProjectHelper.addMarker(f2, AndroidConstants.MARKER_AAPT, message, line, - severity); - } else { - BaseProjectHelper.addMarker(f2, AndroidConstants.MARKER_AAPT, message, severity); - } - } - - return true; - } - - /** - * Returns a matching matcher for the next line - * @param lines The array of lines - * @param nextIndex The index of the next line - * @param pattern The pattern to match - * @return null if error or no match, the matcher otherwise. - */ - private final Matcher getNextLineMatcher(ArrayList<String> lines, - int nextIndex, Pattern pattern) { - // unless we can't, because we reached the last line - if (nextIndex == lines.size()) { - // we expected a 2nd line, so we flag as error - // and we bail - return null; - } - - Matcher m = pattern.matcher(lines.get(nextIndex)); - if (m.matches()) { - return m; - } - - return null; - } - - private IResource getResourceFromFullPath(String filename, String root, - IProject project) { - if (filename.startsWith(root)) { - String file = filename.substring(root.length()); - - // get the resource - IResource r = project.findMember(file); - - // if the resource is valid, we add the marker - if (r.exists()) { - return r; - } - } - - return null; - } - - /** - * Returns an array of external jar files used by the project. - * @return an array of OS-specific absolute file paths - */ - protected final String[] getExternalJars() { - // get the current project - IProject project = getProject(); - - // get a java project from it - IJavaProject javaProject = JavaCore.create(project); - - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - - ArrayList<String> oslibraryList = new ArrayList<String>(); - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY || - e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - // if this is a classpath variable reference, we resolve it. - if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - e = JavaCore.getResolvedClasspathEntry(e); - } - - // get the IPath - IPath path = e.getPath(); - - // check the name ends with .jar - if (AndroidConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) { - boolean local = false; - IResource resource = wsRoot.findMember(path); - if (resource != null && resource.exists() && - resource.getType() == IResource.FILE) { - local = true; - oslibraryList.add(resource.getLocation().toOSString()); - } - - if (local == false) { - // if the jar path doesn't match a workspace resource, - // then we get an OSString and check if this links to a valid file. - String osFullPath = path.toOSString(); - - File f = new File(osFullPath); - if (f.exists()) { - oslibraryList.add(osFullPath); - } else { - String message = String.format( Messages.Couldnt_Locate_s_Error, - path); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, - project, message); - - // Also put a warning marker on the project - markProject(AdtConstants.MARKER_ADT, message, - IMarker.SEVERITY_WARNING); - } - } - } - } - } - } - - return oslibraryList.toArray(new String[oslibraryList.size()]); - } - - /** - * Aborts the build if the SDK/project setups are broken. This does not - * display any errors. - * - * @param javaProject The {@link IJavaProject} being compiled. - * @throws CoreException - */ - protected final void abortOnBadSetup(IProject project) throws CoreException { - // check if we have finished loading the SDK. - if (AdtPlugin.getDefault().getSdkLoadStatus() != LoadStatus.LOADED) { - // we exit silently - stopBuild("SDK is not loaded yet"); - } - - // check the compiler compliance level. - if (ProjectHelper.checkCompilerCompliance(project) != - ProjectHelper.COMPILER_COMPLIANCE_OK) { - // we exit silently - stopBuild(Messages.Compiler_Compliance_Error); - } - - // Check that the SDK directory has been setup. - String osSdkFolder = AdtPlugin.getOsSdkFolder(); - - if (osSdkFolder == null || osSdkFolder.length() == 0) { - stopBuild(Messages.No_SDK_Setup_Error); - } - - IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project); - if (projectTarget == null) { - // no target. error has been output by the container initializer: - // exit silently. - stopBuild("Project has no target"); - } - } - - /** - * Throws an exception to cancel the build. - * - * @param error the error message - * @param args the printf-style arguments to the error message. - * @throws CoreException - */ - protected final void stopBuild(String error, Object... args) throws CoreException { - throw new CoreException(new Status(IStatus.CANCEL, AdtPlugin.PLUGIN_ID, - String.format(error, args))); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java deleted file mode 100644 index 26d96d7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2008 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.build; - -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; - -import java.io.File; -import java.io.PrintStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - -/** - * Wrapper to access dex.jar through reflection. - * <p/>Since there is no proper api to call the method in the dex library, this wrapper is going - * to access it through reflection. - */ -public final class DexWrapper { - - private final static String DEX_MAIN = "com.android.dx.command.dexer.Main"; //$NON-NLS-1$ - private final static String DEX_CONSOLE = "com.android.dx.command.DxConsole"; //$NON-NLS-1$ - private final static String DEX_ARGS = "com.android.dx.command.dexer.Main$Arguments"; //$NON-NLS-1$ - - private final static String MAIN_RUN = "run"; //$NON-NLS-1$ - - private Method mRunMethod; - - private Constructor<?> mArgConstructor; - private Field mArgOutName; - private Field mArgVerbose; - private Field mArgJarOutput; - private Field mArgFileNames; - - private Field mConsoleOut; - private Field mConsoleErr; - - /** - * Loads the dex library from a file path. The loaded library can be used with the - * {@link DexWrapper} object returned by {@link #getWrapper()} - * @param osFilepath the location of the dex.jar file. - * @return an IStatus indicating the result of the load. - */ - public synchronized IStatus loadDex(String osFilepath) { - try { - File f = new File(osFilepath); - if (f.isFile() == false) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( - Messages.DexWrapper_s_does_not_exists, osFilepath)); - } - URL url = f.toURL(); - - URLClassLoader loader = new URLClassLoader(new URL[] { url }, - DexWrapper.class.getClassLoader()); - - // get the classes. - Class<?> mainClass = loader.loadClass(DEX_MAIN); - Class<?> consoleClass = loader.loadClass(DEX_CONSOLE); - Class<?> argClass = loader.loadClass(DEX_ARGS); - - try { - // now get the fields/methods we need - mRunMethod = mainClass.getMethod(MAIN_RUN, argClass); - - mArgConstructor = argClass.getConstructor(); - mArgOutName = argClass.getField("outName"); //$NON-NLS-1$ - mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$ - mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$ - mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$ - - mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$ - mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$ - - } catch (SecurityException e) { - return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e); - } catch (NoSuchMethodException e) { - return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e); - } catch (NoSuchFieldException e) { - return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e); - } - - return Status.OK_STATUS; - } catch (MalformedURLException e) { - // really this should not happen. - return createErrorStatus( - String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e); - } catch (ClassNotFoundException e) { - return createErrorStatus( - String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e); - } - } - - /** - * Runs the dex command. - * @param osOutFilePath the OS path to the outputfile (classes.dex - * @param osFilenames list of input source files (.class and .jar files) - * @param verbose verbose mode. - * @param outStream the stdout console - * @param errStream the stderr console - * @return the integer return code of com.android.dx.command.dexer.Main.run() - * @throws CoreException - */ - public synchronized int run(String osOutFilePath, String[] osFilenames, - boolean verbose, PrintStream outStream, PrintStream errStream) throws CoreException { - - try { - // set the stream - mConsoleErr.set(null /* obj: static field */, errStream); - mConsoleOut.set(null /* obj: static field */, outStream); - - // create the Arguments object. - Object args = mArgConstructor.newInstance(); - mArgOutName.set(args, osOutFilePath); - mArgFileNames.set(args, osFilenames); - mArgJarOutput.set(args, false); - mArgVerbose.set(args, verbose); - - // call the run method - Object res = mRunMethod.invoke(null /* obj: static method */, args); - - if (res instanceof Integer) { - return ((Integer)res).intValue(); - } - - return -1; - } catch (IllegalAccessException e) { - throw new CoreException(createErrorStatus( - String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, e.getMessage()), e)); - } catch (InstantiationException e) { - throw new CoreException(createErrorStatus( - String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, e.getMessage()), e)); - } catch (InvocationTargetException e) { - throw new CoreException(createErrorStatus( - String.format(Messages.DexWrapper_Unable_To_Execute_Dex_s, e.getMessage()), e)); - } - } - - private static IStatus createErrorStatus(String message, Exception e) { - AdtPlugin.log(e, message); - AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message); - - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, e); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/Messages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/Messages.java deleted file mode 100644 index 0100049..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/Messages.java +++ /dev/null @@ -1,137 +0,0 @@ - -package com.android.ide.eclipse.adt.build; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS { - private static final String BUNDLE_NAME = "com.android.ide.eclipse.adt.build.build_messages"; //$NON-NLS-1$ - - public static String AAPT_Error; - - public static String AAPT_Exec_Error; - - public static String Added_s_s_Needs_Updating; - - public static String AIDL_Exec_Error; - - public static String AIDL_Java_Conflict; - - public static String ApkBuilder_Certificate_Expired_on_s; - - public static String ApkBuilder_JAVA_HOME_is_s; - - public static String ApkBuilder_Packaging_s; - - public static String ApkBuilder_Packaging_s_into_s; - - public static String ApkBuilder_s_Conflict_with_file_s; - - public static String ApkBuilder_Signing_Key_Creation_s; - - public static String ApkBuilder_Unable_To_Gey_Key; - - public static String ApkBuilder_UnableBuild_Dex_Not_loaded; - - public static String ApkBuilder_Update_or_Execute_manually_s; - - public static String ApkBuilder_Using_Default_Key; - - public static String ApkBuilder_Using_s_To_Sign; - - public static String Checking_Package_Change; - - public static String Compiler_Compliance_Error; - - public static String Couldnt_Locate_s_Error; - - public static String Dalvik_Error_d; - - public static String Dalvik_Error_s; - - public static String Delete_Obsolete_Error; - - public static String DexWrapper_Dex_Loader; - - public static String DexWrapper_Failed_to_load_s; - - public static String DexWrapper_s_does_not_exists; - - public static String DexWrapper_SecuryEx_Unable_To_Find_API; - - public static String DexWrapper_SecuryEx_Unable_To_Find_Field; - - public static String DexWrapper_SecuryEx_Unable_To_Find_Method; - - public static String DexWrapper_Unable_To_Execute_Dex_s; - - public static String DX_Jar_Error; - - public static String Failed_To_Get_Output; - - public static String Final_Archive_Error_s; - - public static String Incompatible_VM_Warning; - - public static String Marker_Delete_Error; - - public static String No_SDK_Setup_Error; - - public static String Nothing_To_Compile; - - public static String Output_Missing; - - public static String Package_s_Doesnt_Exist_Error; - - public static String Preparing_Generated_Files; - - public static String Project_Has_Errors; - - public static String Refreshing_Res; - - public static String Removing_Generated_Classes; - - public static String Requires_1_5_Error; - - public static String Requires_Class_Compatibility_5; - - public static String Requires_Compiler_Compliance_5; - - public static String Requires_Source_Compatibility_5; - - public static String s_Contains_Xml_Error; - - public static String s_Doesnt_Declare_Package_Error; - - public static String s_File_Missing; - - public static String s_Missing_Repackaging; - - public static String s_Modified_Manually_Recreating_s; - - public static String s_Modified_Recreating_s; - - public static String s_Removed_Recreating_s; - - public static String s_Removed_s_Needs_Updating; - - public static String Start_Full_Apk_Build; - - public static String Start_Full_Pre_Compiler; - - public static String Start_Inc_Apk_Build; - - public static String Start_Inc_Pre_Compiler; - - public static String Unparsed_AAPT_Errors; - - public static String Unparsed_AIDL_Errors; - - public static String Xml_Error; - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java deleted file mode 100644 index 958cac2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java +++ /dev/null @@ -1,1150 +0,0 @@ -/* - * Copyright (C) 2007 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.build; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.FixLaunchConfig; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.ide.eclipse.common.project.AndroidManifestParser; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.common.project.XmlErrorHandler.BasicXmlErrorListener; -import com.android.sdklib.IAndroidTarget; - -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.IResourceDelta; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourceAttributes; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Pre Java Compiler. - * This incremental builder performs 2 tasks: - * <ul> - * <li>compiles the resources located in the res/ folder, along with the - * AndroidManifest.xml file into the R.java class.</li> - * <li>compiles any .aidl files into a corresponding java file.</li> - * </ul> - * - */ -public class PreCompilerBuilder extends BaseBuilder { - - public static final String ID = "com.android.ide.eclipse.adt.PreCompilerBuilder"; //$NON-NLS-1$ - - private static final String PROPERTY_PACKAGE = "manifestPackage"; //$NON-NLS-1$ - - private static final String PROPERTY_SOURCE_FOLDER = - "manifestPackageSourceFolder"; //$NON-NLS-1$ - - private static final String PROPERTY_COMPILE_RESOURCES = "compileResources"; //$NON-NLS-1$ - - static final String PROPERTY_ANDROID_GENERATED = "androidGenerated"; //$NON-NLS-1$ - static final String PROPERTY_ANDROID_CONFLICT = "androidConflict"; //$NON-NLS-1$ - - /** - * Single line aidl error<br> - * "<path>:<line>: <error>" - */ - private static Pattern sAidlPattern1 = Pattern.compile("^(.+?):(\\d+):\\s(.+)$"); //$NON-NLS-1$ - - /** - * Compile flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resources, if - * this flag is true, then we know we'll have to compile the resources - * into R.java - */ - private boolean mCompileResources = false; - - /** List of .aidl files found that are modified or new. */ - private final ArrayList<IFile> mAidlToCompile = new ArrayList<IFile>(); - - /** List of .aidl files that have been removed. */ - private final ArrayList<IFile> mAidlToRemove = new ArrayList<IFile>(); - - /** cache of the java package defined in the manifest */ - private String mManifestPackage; - - /** Source folder containing the java package defined in the manifest. */ - private IFolder mManifestPackageSourceFolder; - - /** - * Progress monitor waiting the end of the process to set a persistent value - * in a file. This is typically used in conjunction with <code>IResource.refresh()</code>, - * since this call is asysnchronous, and we need to wait for it to finish for the file - * to be known by eclipse, before we can call <code>resource.setPersistentProperty</code> on - * a new file. - */ - private static class RefreshProgressMonitor implements IProgressMonitor { - private boolean mCancelled = false; - private IFile mNewFile; - private IFile mSource; - private boolean mDoneExecuted = false; - public RefreshProgressMonitor(IFile newFile, IFile source) { - mNewFile = newFile; - mSource = source; - } - - public void beginTask(String name, int totalWork) { - } - - public void done() { - if (mDoneExecuted == false) { - mDoneExecuted = true; - if (mNewFile.exists()) { - ProjectHelper.saveResourceProperty(mNewFile, PROPERTY_ANDROID_GENERATED, - mSource); - try { - mNewFile.setDerived(true); - } catch (CoreException e) { - // This really shouldn't happen since we check that the resource exist. - // Worst case scenario, the resource isn't marked as derived. - } - } - } - } - - public void internalWorked(double work) { - } - - public boolean isCanceled() { - return mCancelled; - } - - public void setCanceled(boolean value) { - mCancelled = value; - } - - public void setTaskName(String name) { - } - - public void subTask(String name) { - } - - public void worked(int work) { - } - } - - /** - * Progress Monitor setting up to two files as derived once their parent is refreshed. - * This is used as ProgressMonitor to refresh the R.java/Manifest.java parent (to display - * the newly created files in the package explorer). - */ - private static class DerivedProgressMonitor implements IProgressMonitor { - private boolean mCancelled = false; - private IFile mFile1; - private IFile mFile2; - private boolean mDoneExecuted = false; - public DerivedProgressMonitor(IFile file1, IFile file2) { - mFile1 = file1; - mFile2 = file2; - } - - public void beginTask(String name, int totalWork) { - } - - public void done() { - if (mDoneExecuted == false) { - if (mFile1 != null && mFile1.exists()) { - mDoneExecuted = true; - try { - mFile1.setDerived(true); - } catch (CoreException e) { - // This really shouldn't happen since we check that the resource edit. - // Worst case scenario, the resource isn't marked as derived. - } - } - if (mFile2 != null && mFile2.exists()) { - try { - mFile2.setDerived(true); - } catch (CoreException e) { - // This really shouldn't happen since we check that the resource edit. - // Worst case scenario, the resource isn't marked as derived. - } - } - } - } - - public void internalWorked(double work) { - } - - public boolean isCanceled() { - return mCancelled; - } - - public void setCanceled(boolean value) { - mCancelled = value; - } - - public void setTaskName(String name) { - } - - public void subTask(String name) { - } - - public void worked(int work) { - } - } - - public PreCompilerBuilder() { - super(); - } - - // build() returns a list of project from which this project depends for future compilation. - @SuppressWarnings("unchecked") //$NON-NLS-1$ - @Override - protected IProject[] build(int kind, Map args, IProgressMonitor monitor) - throws CoreException { - // First thing we do is go through the resource delta to not - // lose it if we have to abort the build for any reason. - - // get the project objects - IProject project = getProject(); - IJavaProject javaProject = JavaCore.create(project); - IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project); - - // now we need to get the classpath list - ArrayList<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject); - - PreCompilerDeltaVisitor dv = null; - String javaPackage = null; - - if (kind == FULL_BUILD) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Start_Full_Pre_Compiler); - mCompileResources = true; - buildAidlCompilationList(project, sourceList); - } else { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Start_Inc_Pre_Compiler); - - // Go through the resources and see if something changed. - // Even if the mCompileResources flag is true from a previously aborted - // build, we need to go through the Resource delta to get a possible - // list of aidl files to compile/remove. - IResourceDelta delta = getDelta(project); - if (delta == null) { - mCompileResources = true; - buildAidlCompilationList(project, sourceList); - } else { - dv = new PreCompilerDeltaVisitor(this, sourceList); - delta.accept(dv); - - // record the state - mCompileResources |= dv.getCompileResources(); - - // handle aidl modification - if (dv.getFullAidlRecompilation()) { - buildAidlCompilationList(project, sourceList); - } else { - mergeAidlFileModifications(dv.getAidlToCompile(), - dv.getAidlToRemove()); - } - - // get the java package from the visitor - javaPackage = dv.getManifestPackage(); - } - } - - // store the build status in the persistent storage - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , mCompileResources); - // TODO also needs to store the list of aidl to compile/remove - - // At this point we have stored what needs to be build, so we can - // do some high level test and abort if needed. - abortOnBadSetup(project); - - // if there was some XML errors, we just return w/o doing - // anything since we've put some markers in the files anyway. - if (dv != null && dv.mXmlError) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Xml_Error); - - // This interrupts the build. The next builders will not run. - stopBuild(Messages.Xml_Error); - } - - - // get the manifest file - IFile manifest = AndroidManifestHelper.getManifest(project); - - if (manifest == null) { - String msg = String.format(Messages.s_File_Missing, - AndroidConstants.FN_ANDROID_MANIFEST); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } - - // lets check the XML of the manifest first, if that hasn't been done by the - // resource delta visitor yet. - if (dv == null || dv.getCheckedManifestXml() == false) { - BasicXmlErrorListener errorListener = new BasicXmlErrorListener(); - AndroidManifestParser parser = BaseProjectHelper.parseManifestForError(manifest, - errorListener); - - if (errorListener.mHasXmlError == true) { - // there was an error in the manifest, its file has been marked, - // by the XmlErrorHandler. - // We return; - String msg = String.format(Messages.s_Contains_Xml_Error, - AndroidConstants.FN_ANDROID_MANIFEST); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } - - // get the java package from the parser - javaPackage = parser.getPackage(); - } - - if (javaPackage == null || javaPackage.length() == 0) { - // looks like the AndroidManifest file isn't valid. - String msg = String.format(Messages.s_Doesnt_Declare_Package_Error, - AndroidConstants.FN_ANDROID_MANIFEST); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - msg); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } - - // at this point we have the java package. We need to make sure it's not a different package - // than the previous one that were built. - if (javaPackage.equals(mManifestPackage) == false) { - // The manifest package has changed, the user may want to update - // the launch configuration - if (mManifestPackage != null) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Checking_Package_Change); - - FixLaunchConfig flc = new FixLaunchConfig(project, mManifestPackage, javaPackage); - flc.start(); - } - - // now we delete the generated classes from their previous location - deleteObsoleteGeneratedClass(AndroidConstants.FN_RESOURCE_CLASS, - mManifestPackageSourceFolder, mManifestPackage); - deleteObsoleteGeneratedClass(AndroidConstants.FN_MANIFEST_CLASS, - mManifestPackageSourceFolder, mManifestPackage); - - // record the new manifest package, and save it. - mManifestPackage = javaPackage; - saveProjectStringProperty(PROPERTY_PACKAGE, mManifestPackage); - } - - if (mCompileResources) { - // we need to figure out where to store the R class. - // get the parent folder for R.java and update mManifestPackageSourceFolder - IFolder packageFolder = getManifestPackageFolder(project, sourceList); - - // at this point, either we have found the package or not. - // if we haven't well it's time to tell the user and abort - if (mManifestPackageSourceFolder == null) { - // mark the manifest file - String message = String.format(Messages.Package_s_Doesnt_Exist_Error, - mManifestPackage); - BaseProjectHelper.addMarker(manifest, AndroidConstants.MARKER_AAPT, message, - IMarker.SEVERITY_ERROR); - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, message); - - // abort - // This interrupts the build. The next builders will not run. - stopBuild(message); - } - - - // found the folder in which to write the stuff - - // get the resource folder - IFolder resFolder = project.getFolder(AndroidConstants.WS_RESOURCES); - - // get the file system path - IPath outputLocation = mManifestPackageSourceFolder.getLocation(); - IPath resLocation = resFolder.getLocation(); - IPath manifestLocation = manifest.getLocation(); - - // those locations have to exist for us to do something! - if (outputLocation != null && resLocation != null - && manifestLocation != null) { - String osOutputPath = outputLocation.toOSString(); - String osResPath = resLocation.toOSString(); - String osManifestPath = manifestLocation.toOSString(); - - // remove the aapt markers - removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT); - removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT); - - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Preparing_Generated_Files); - - // since the R.java file may be already existing in read-only - // mode we need to make it readable so that aapt can overwrite - // it - IFile rJavaFile = packageFolder.getFile(AndroidConstants.FN_RESOURCE_CLASS); - prepareFileForExternalModification(rJavaFile); - - // do the same for the Manifest.java class - IFile manifestJavaFile = packageFolder.getFile(AndroidConstants.FN_MANIFEST_CLASS); - prepareFileForExternalModification(manifestJavaFile); - - // we actually need to delete the manifest.java as it may become empty and in this - // case aapt doesn't generate an empty one, but instead doesn't touch it. - manifestJavaFile.delete(true, null); - - // launch aapt: create the command line - ArrayList<String> array = new ArrayList<String>(); - array.add(projectTarget.getPath(IAndroidTarget.AAPT)); - array.add("package"); //$NON-NLS-1$ - array.add("-m"); //$NON-NLS-1$ - if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) { - array.add("-v"); //$NON-NLS-1$ - } - array.add("-J"); //$NON-NLS-1$ - array.add(osOutputPath); - array.add("-M"); //$NON-NLS-1$ - array.add(osManifestPath); - array.add("-S"); //$NON-NLS-1$ - array.add(osResPath); - array.add("-I"); //$NON-NLS-1$ - array.add(projectTarget.getPath(IAndroidTarget.ANDROID_JAR)); - - if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) { - StringBuilder sb = new StringBuilder(); - for (String c : array) { - sb.append(c); - sb.append(' '); - } - String cmd_line = sb.toString(); - AdtPlugin.printToConsole(project, cmd_line); - } - - // launch - int execError = 1; - try { - // launch the command line process - Process process = Runtime.getRuntime().exec( - array.toArray(new String[array.size()])); - - // list to store each line of stderr - ArrayList<String> results = new ArrayList<String>(); - - // get the output and return code from the process - execError = grabProcessOutput(process, results); - - // attempt to parse the error output - boolean parsingError = parseAaptOutput(results, project); - - // if we couldn't parse the output we display it in the console. - if (parsingError) { - if (execError != 0) { - AdtPlugin.printErrorToConsole(project, results.toArray()); - } else { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_NORMAL, - project, results.toArray()); - } - } - - if (execError != 0) { - // if the exec failed, and we couldn't parse the error output (and therefore - // not all files that should have been marked, were marked), we put a - // generic marker on the project and abort. - if (parsingError) { - markProject(AdtConstants.MARKER_ADT, Messages.Unparsed_AAPT_Errors, - IMarker.SEVERITY_ERROR); - } - - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.AAPT_Error); - - // abort if exec failed. - // This interrupts the build. The next builders will not run. - stopBuild(Messages.AAPT_Error); - } - } catch (IOException e1) { - // something happen while executing the process, - // mark the project and exit - String msg = String.format(Messages.AAPT_Exec_Error, array.get(0)); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } catch (InterruptedException e) { - // we got interrupted waiting for the process to end... - // mark the project and exit - String msg = String.format(Messages.AAPT_Exec_Error, array.get(0)); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - - // This interrupts the build. The next builders will not run. - stopBuild(msg); - } - - // if the return code was OK, we refresh the folder that - // contains R.java to force a java recompile. - if (execError == 0) { - // now set the R.java/Manifest.java file as read only. - finishJavaFilesAfterExternalModification(rJavaFile, manifestJavaFile); - - // build has been done. reset the state of the builder - mCompileResources = false; - - // and store it - saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, mCompileResources); - } - } - } else { - // nothing to do - } - - // now handle the aidl stuff. - // look for a preprocessed aidl file - IResource projectAidl = project.findMember("project.aidl"); //$NON-NLS-1$ - String folderAidlPath = null; - if (projectAidl != null && projectAidl.exists()) { - folderAidlPath = projectAidl.getLocation().toOSString(); - } - boolean aidlStatus = handleAidl(projectTarget, sourceList, folderAidlPath, monitor); - - if (aidlStatus == false && mCompileResources == false) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Nothing_To_Compile); - } - - return null; - } - - @Override - protected void clean(IProgressMonitor monitor) throws CoreException { - super.clean(monitor); - - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), - Messages.Removing_Generated_Classes); - - // check if we have the R.java info already. - if (mManifestPackageSourceFolder != null && mManifestPackage != null) { - deleteObsoleteGeneratedClass(AndroidConstants.FN_RESOURCE_CLASS, - mManifestPackageSourceFolder, mManifestPackage); - deleteObsoleteGeneratedClass(AndroidConstants.FN_MANIFEST_CLASS, - mManifestPackageSourceFolder, mManifestPackage); - } - - // FIXME: delete all java generated from aidl. - } - - @Override - protected void startupOnInitialize() { - super.startupOnInitialize(); - - // load the previous IFolder and java package. - mManifestPackage = loadProjectStringProperty(PROPERTY_PACKAGE); - IResource resource = loadProjectResourceProperty(PROPERTY_SOURCE_FOLDER); - if (resource instanceof IFolder) { - mManifestPackageSourceFolder = (IFolder)resource; - } - - // Load the current compile flag. We ask for true if not found to force a - // recompile. - mCompileResources = loadProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, true); - } - - /** - * Delete the a generated java class associated with the specified java package. - * @param filename Name of the generated file to remove. - * @param sourceFolder The source Folder containing the old java package. - * @param javaPackage the old java package - */ - private void deleteObsoleteGeneratedClass(String filename, IFolder sourceFolder, - String javaPackage) { - if (sourceFolder == null || javaPackage == null) { - return; - } - - // convert the java package into path - String[] segments = javaPackage.split(AndroidConstants.RE_DOT); - - StringBuilder path = new StringBuilder(); - for (String s : segments) { - path.append(AndroidConstants.WS_SEP_CHAR); - path.append(s); - } - - // appends the name of the generated file - path.append(AndroidConstants.WS_SEP_CHAR); - path.append(filename); - - Path iPath = new Path(path.toString()); - - // Find a matching resource object. - IResource javaFile = sourceFolder.findMember(iPath); - if (javaFile != null && javaFile.exists() && javaFile.getType() == IResource.FILE) { - try { - // remove the read-only tag - prepareFileForExternalModification((IFile)javaFile); - - // delete - javaFile.delete(true, null); - - // refresh parent - javaFile.getParent().refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor()); - - } catch (CoreException e) { - // failed to delete it, the user will have to delete it manually. - String message = String.format(Messages.Delete_Obsolete_Error, path); - IProject project = getProject(); - AdtPlugin.printErrorToConsole(project, message); - AdtPlugin.printErrorToConsole(project, e.getMessage()); - } - } - } - - /** - * Looks for the folder containing the package defined in the manifest. It looks in the - * list of source folders for the one containing folders matching the package defined in the - * manifest (from the field <code>mManifestPackage</code>). It returns the final folder, which - * will contain the R class, and update the field <code>mManifestPackageSourceFolder</code> - * to be the source folder containing the full package. - * @param project The project. - * @param sourceList The list of source folders for the project. - * @return the package that will contain the R class or null if the folder was not found. - * @throws CoreException - */ - private IFolder getManifestPackageFolder(IProject project, ArrayList<IPath> sourceList) - throws CoreException { - // split the package in segments - String[] packageSegments = mManifestPackage.split(AndroidConstants.RE_DOT); - - // we look for 2 folders. - // 1. The source folder that contains the full java package. - // we will store the folder in the field mJavaSourceFolder, for reuse during - IFolder manifestPackageSourceFolder = null; - // subsequent builds. This is the folder we will give to aapt. - // 2. The folder actually containing the R.java files. We need this one to do a refresh - IFolder packageFolder = null; - - for (IPath iPath : sourceList) { - int packageSegmentIndex = 0; - - // the path is relative to the workspace. We ignore the first segment, - // when getting the resource from the IProject object. - IResource classpathEntry = project.getFolder(iPath.removeFirstSegments(1)); - - if (classpathEntry instanceof IFolder) { - IFolder classpathFolder = (IFolder)classpathEntry; - IFolder folder = classpathFolder; - - boolean failed = false; - while (failed == false - && packageSegmentIndex < packageSegments.length) { - - // loop on that folder content looking for folders - // that match the package - // defined in AndroidManifest.xml - - // get the folder content - IResource[] content = folder.members(); - - // this is the segment we look for - String segment = packageSegments[packageSegmentIndex]; - - // did we find it at this level - boolean found = false; - - for (IResource r : content) { - // look for the java package segment - if (r instanceof IFolder) { - if (r.getName().equals(segment)) { - // we need to skip to the next one - folder = (IFolder)r; - packageSegmentIndex++; - found = true; - break; - } - } - } - - // if we didn't find it at this level we just fail. - if (found == false) { - failed = true; - } - } - - // if we didn't fail then we found it. no point in - // looping through the rest - // or the classpathEntry - if (failed == false) { - // save the target folder reference - manifestPackageSourceFolder = classpathFolder; - packageFolder = folder; - break; - } - } - } - - // save the location of the folder into the persistent storage - if (manifestPackageSourceFolder != mManifestPackageSourceFolder) { - mManifestPackageSourceFolder = manifestPackageSourceFolder; - saveProjectResourceProperty(PROPERTY_SOURCE_FOLDER, mManifestPackageSourceFolder); - } - return packageFolder; - } - - /** - * Compiles aidl files into java. This will also removes old java files - * created from aidl files that are now gone. - * @param projectTarget Target of the project - * @param sourceFolders the list of source folders, relative to the workspace. - * @param folderAidlPath - * @param monitor the projess monitor - * @returns true if it did something - * @throws CoreException - */ - private boolean handleAidl(IAndroidTarget projectTarget, ArrayList<IPath> sourceFolders, - String folderAidlPath, IProgressMonitor monitor) throws CoreException { - if (mAidlToCompile.size() == 0 && mAidlToRemove.size() == 0) { - return false; - } - - - // create the command line - String[] command = new String[4 + sourceFolders.size() + (folderAidlPath != null ? 1 : 0)]; - int index = 0; - int aidlIndex; - command[index++] = projectTarget.getPath(IAndroidTarget.AIDL); - command[aidlIndex = index++] = "-p"; //$NON-NLS-1$ - if (folderAidlPath != null) { - command[index++] = "-p" + folderAidlPath; //$NON-NLS-1$ - } - - // since the path are relative to the workspace and not the project itself, we need - // the workspace root. - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - for (IPath p : sourceFolders) { - IFolder f = wsRoot.getFolder(p); - command[index++] = "-I" + f.getLocation().toOSString(); //$NON-NLS-1$ - } - - // list of files that have failed compilation. - ArrayList<IFile> stillNeedCompilation = new ArrayList<IFile>(); - - // if an aidl file is being removed before we managed to compile it, it'll be in - // both list. We *need* to remove it from the compile list or it'll never go away. - for (IFile aidlFile : mAidlToRemove) { - int pos = mAidlToCompile.indexOf(aidlFile); - if (pos != -1) { - mAidlToCompile.remove(pos); - } - } - - // loop until we've compile them all - for (IFile aidlFile : mAidlToCompile) { - // Remove the AIDL error markers from the aidl file - removeMarkersFromFile(aidlFile, AndroidConstants.MARKER_AIDL); - - // get the path - IPath iPath = aidlFile.getLocation(); - String osPath = iPath.toOSString(); - - // get the parent container - IContainer parentContainer = aidlFile.getParent(); - - // replace the extension in both the full path and the - // last segment - String osJavaPath = osPath.replaceAll(AndroidConstants.RE_AIDL_EXT, - AndroidConstants.DOT_JAVA); - String javaName = aidlFile.getName().replaceAll(AndroidConstants.RE_AIDL_EXT, - AndroidConstants.DOT_JAVA); - - // check if we can compile it, or if there is a conflict with a java file - boolean conflict = ProjectHelper.loadBooleanProperty(aidlFile, - PROPERTY_ANDROID_CONFLICT, false); - if (conflict) { - String msg = String.format(Messages.AIDL_Java_Conflict, javaName, - aidlFile.getName()); - - // put a marker - BaseProjectHelper.addMarker(aidlFile, AndroidConstants.MARKER_AIDL, msg, - IMarker.SEVERITY_ERROR); - - // output an error - AdtPlugin.printErrorToConsole(getProject(), msg); - - stillNeedCompilation.add(aidlFile); - - // move on to next file - continue; - } - - // get the resource for the java file. - Path javaIPath = new Path(javaName); - IFile javaFile = parentContainer.getFile(javaIPath); - - // if the file was read-only, this will make it readable. - prepareFileForExternalModification(javaFile); - - // finish to set the command line. - command[aidlIndex] = "-p" + Sdk.getCurrent().getTarget(aidlFile.getProject()).getPath( - IAndroidTarget.ANDROID_AIDL); //$NON-NLS-1$ - command[index] = osPath; - command[index + 1] = osJavaPath; - - // launch the process - if (execAidl(command, aidlFile) == false) { - // aidl failed. File should be marked. We add the file to the list - // of file that will need compilation again. - stillNeedCompilation.add(aidlFile); - - // and we move on to the next one. - continue; - } else { - // since the exec worked, we refresh the parent, and set the - // file as read only. - finishFileAfterExternalModification(javaFile, aidlFile); - } - } - - // change the list to only contains the file that have failed compilation - mAidlToCompile.clear(); - mAidlToCompile.addAll(stillNeedCompilation); - - // Remove the java files created from aidl files that have been removed. - for (IFile aidlFile : mAidlToRemove) { - // make the java filename - String javaName = aidlFile.getName().replaceAll( - AndroidConstants.RE_AIDL_EXT, - AndroidConstants.DOT_JAVA); - - // get the parent container - IContainer ic = aidlFile.getParent(); - - // and get the IFile corresponding to the java file. - IFile javaFile = ic.getFile(new Path(javaName)); - if (javaFile != null && javaFile.exists() ) { - // check if this java file has a persistent data marking it as generated by - // the builder. - // While we put the aidl path as a resource, internally it's all string anyway. - // We use loadStringProperty, because loadResourceProperty tries to match - // the string value (a path in this case) with an existing resource, but - // the aidl file was deleted, so it would return null, even though the property - // existed. - String aidlPath = ProjectHelper.loadStringProperty(javaFile, - PROPERTY_ANDROID_GENERATED); - - if (aidlPath != null) { - // This confirms the java file was generated by the builder, - // we can delete the aidlFile. - javaFile.delete(true, null); - - // Refresh parent. - ic.refreshLocal(IResource.DEPTH_ONE, monitor); - } - } - } - mAidlToRemove.clear(); - - return true; - } - - /** - * Execute the aidl command line, parse the output, and mark the aidl file - * with any reported errors. - * @param command the String array containing the command line to execute. - * @param file The IFile object representing the aidl file being - * compiled. - * @return false if the exec failed, and build needs to be aborted. - */ - private boolean execAidl(String[] command, IFile file) { - // do the exec - try { - Process p = Runtime.getRuntime().exec(command); - - // list to store each line of stderr - ArrayList<String> results = new ArrayList<String>(); - - // get the output and return code from the process - int result = grabProcessOutput(p, results); - - // attempt to parse the error output - boolean error = parseAidlOutput(results, file); - - // If the process failed and we couldn't parse the output - // we pring a message, mark the project and exit - if (result != 0 && error == true) { - // display the message in the console. - AdtPlugin.printErrorToConsole(getProject(), results.toArray()); - - // mark the project and exit - markProject(AdtConstants.MARKER_ADT, Messages.Unparsed_AIDL_Errors, - IMarker.SEVERITY_ERROR); - return false; - } - } catch (IOException e) { - // mark the project and exit - String msg = String.format(Messages.AIDL_Exec_Error, command[0]); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } catch (InterruptedException e) { - // mark the project and exit - String msg = String.format(Messages.AIDL_Exec_Error, command[0]); - markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR); - return false; - } - - return true; - } - - /** - * Goes through the build paths and fills the list of aidl files to compile - * ({@link #mAidlToCompile}). - * @param project The project. - * @param buildPaths The list of build paths. - */ - private void buildAidlCompilationList(IProject project, - ArrayList<IPath> buildPaths) { - for (IPath p : buildPaths) { - // Because the path contains the name of the project as well, we - // need to remove it, to access the final folder. - String[] segments = p.segments(); - IContainer folder = project; - for (int i = 1; i < segments.length; i++) { - IResource r = folder.findMember(segments[i]); - if (r != null && r.exists() && - r.getType() == IResource.FOLDER) { - folder = (IContainer)r; - } else { - // hmm looks like the build path is corrupted/wrong. - // reset and break - folder = project; - break; - } - } - - // did we ge a folder? - if (folder != project) { - // then we scan! - scanContainerForAidl(folder); - } - } - } - - /** - * Scans a container and fills the list of aidl files to compile. - * @param container The container to scan. - */ - private void scanContainerForAidl(IContainer container) { - try { - IResource[] members = container.members(); - for (IResource r : members) { - // get the type of the resource - switch (r.getType()) { - case IResource.FILE: - // if this a file, check that the file actually exist - // and that it's an aidl file - if (r.exists() && - AndroidConstants.EXT_AIDL.equalsIgnoreCase(r.getFileExtension())) { - mAidlToCompile.add((IFile)r); - } - break; - case IResource.FOLDER: - // recursively go through children - scanContainerForAidl((IFolder)r); - break; - default: - // this would mean it's a project or the workspace root - // which is unlikely to happen. we do nothing - break; - } - } - } catch (CoreException e) { - // Couldn't get the members list for some reason. Just return. - } - } - - - /** - * Parse the output of aidl and mark the file with any errors. - * @param lines The output to parse. - * @param file The file to mark with error. - * @return true if the parsing failed, false if success. - */ - private boolean parseAidlOutput(ArrayList<String> lines, IFile file) { - // nothing to parse? just return false; - if (lines.size() == 0) { - return false; - } - - Matcher m; - - for (int i = 0; i < lines.size(); i++) { - String p = lines.get(i); - - m = sAidlPattern1.matcher(p); - if (m.matches()) { - // we can ignore group 1 which is the location since we already - // have a IFile object representing the aidl file. - String lineStr = m.group(2); - String msg = m.group(3); - - // get the line number - int line = 0; - try { - line = Integer.parseInt(lineStr); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid - // file number. Parsing failed and we return true - return true; - } - - // mark the file - BaseProjectHelper.addMarker(file, AndroidConstants.MARKER_AIDL, msg, line, - IMarker.SEVERITY_ERROR); - - // success, go to the next line - continue; - } - - // invalid line format, flag as error, and bail - return true; - } - - return false; - } - - /** - * Merge the current list of aidl file to compile/remove with the new one. - * @param toCompile List of file to compile - * @param toRemove List of file to remove - */ - private void mergeAidlFileModifications(ArrayList<IFile> toCompile, - ArrayList<IFile> toRemove) { - - // loop through the new toRemove list, and add it to the old one, - // plus remove any file that was still to compile and that are now - // removed - for (IFile r : toRemove) { - if (mAidlToRemove.indexOf(r) == -1) { - mAidlToRemove.add(r); - } - - int index = mAidlToCompile.indexOf(r); - if (index != -1) { - mAidlToCompile.remove(index); - } - } - - // now loop through the new files to compile and add it to the list. - // Also look for them in the remove list, this would mean that they - // were removed, then added back, and we shouldn't remove them, just - // recompile them. - for (IFile r : toCompile) { - if (mAidlToCompile.indexOf(r) == -1) { - mAidlToCompile.add(r); - } - - int index = mAidlToRemove.indexOf(r); - if (index != -1) { - mAidlToRemove.remove(index); - } - } - } - - /** - * Prepare an already existing file for modification. File generated from - * command line processed are marked as read-only. This method prepares - * them (mark them as read-write) before the command line process is - * started. A check is made to be sure the file exists. - * @param file The IResource object for the file to prepare. - * @throws CoreException - */ - private void prepareFileForExternalModification(IFile file) - throws CoreException { - // file may not exist yet, so we check that. - if (file != null && file.exists()) { - // get the attributes. - ResourceAttributes ra = file.getResourceAttributes(); - if (ra != null) { - // change the attributes - ra.setReadOnly(false); - - // set the new attributes in the file. - file.setResourceAttributes(ra); - } - } - } - - /** - * Finish a file created/modified by an outside command line process. - * The file is marked as modified by Android, and the parent folder is refreshed, so that, - * in case the file didn't exist beforehand, the file appears in the package explorer. - * @param rFile The R file to "finish". - * @param manifestFile The manifest file to "finish". - * @throws CoreException - */ - private void finishJavaFilesAfterExternalModification(IFile rFile, IFile manifestFile) - throws CoreException { - IContainer parent = rFile.getParent(); - - IProgressMonitor monitor = new DerivedProgressMonitor(rFile, manifestFile); - - // refresh the parent node in the package explorer. Once this is done the custom progress - // monitor will mark them as derived. - parent.refreshLocal(IResource.DEPTH_ONE, monitor); - } - - /** - * Finish a file created/modified by an outside command line process. - * The file is marked as modified by Android, and the parent folder is refreshed, so that, - * in case the file didn't exist beforehand, the file appears in the package explorer. - * @param file The file to "finish". - * @param aidlFile The AIDL file to "finish". - * @throws CoreException - */ - private void finishFileAfterExternalModification(IFile file, IFile aidlFile) - throws CoreException { - IContainer parent = file.getParent(); - - // we need to add a link to the aidl file. - // We need to wait for the refresh of the parent to be done, so we'll do - // it in the monitor. This will also set the file as derived. - IProgressMonitor monitor = new RefreshProgressMonitor(file, aidlFile); - - // refresh the parent node in the package explorer. - parent.refreshLocal(IResource.DEPTH_ONE, monitor); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java deleted file mode 100644 index f4778d7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright (C) 2007 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.build; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.build.BaseBuilder.BaseDeltaVisitor; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestParser; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; - -import java.util.ArrayList; - -/** - * Resource Delta visitor for the pre-compiler. - */ -class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements - IResourceDeltaVisitor { - - // Result fields. - /** - * Compile flag. This is set to true if one of the changed/added/removed - * file is a resource file. Upon visiting all the delta resources, if - * this flag is true, then we know we'll have to compile the resources - * into R.java - */ - private boolean mCompileResources = false; - - /** List of .aidl files found that are modified or new. */ - private final ArrayList<IFile> mAidlToCompile = new ArrayList<IFile>(); - - /** List of .aidl files that have been removed. */ - private final ArrayList<IFile> mAidlToRemove = new ArrayList<IFile>(); - - /** Aidl forced recompilation flag. This is set to true if project.aidl is modified. */ - private boolean mFullAidlCompilation = false; - - /** Manifest check/parsing flag. */ - private boolean mCheckedManifestXml = false; - - /** Application Pacakge, gathered from the parsing of the manifest */ - private String mJavaPackage = null; - - // Internal usage fields. - /** - * In Resource folder flag. This allows us to know if we're in the - * resource folder. - */ - private boolean mInRes = false; - - /** - * In Source folder flag. This allows us to know if we're in a source - * folder. - */ - private boolean mInSrc = false; - - /** List of source folders. */ - private ArrayList<IPath> mSourceFolders; - - - public PreCompilerDeltaVisitor(BaseBuilder builder, ArrayList<IPath> sourceFolders) { - super(builder); - mSourceFolders = sourceFolders; - } - - public boolean getCompileResources() { - return mCompileResources; - } - - public ArrayList<IFile> getAidlToCompile() { - return mAidlToCompile; - } - - public ArrayList<IFile> getAidlToRemove() { - return mAidlToRemove; - } - - public boolean getFullAidlRecompilation() { - return mFullAidlCompilation; - } - - /** - * Returns whether the manifest file was parsed/checked for error during the resource delta - * visiting. - */ - public boolean getCheckedManifestXml() { - return mCheckedManifestXml; - } - - /** - * Returns the manifest package if the manifest was checked/parsed. - * <p/> - * This can return null in two cases: - * <ul> - * <li>The manifest was not part of the resource change delta, and the manifest was - * not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li> - * <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>), - * but the package declaration is missing</li> - * </ul> - * @return the manifest package or null. - */ - public String getManifestPackage() { - return mJavaPackage; - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.core.resources.IResourceDeltaVisitor - * #visit(org.eclipse.core.resources.IResourceDelta) - */ - public boolean visit(IResourceDelta delta) throws CoreException { - // we are only going to look for changes in res/, source folders and in - // AndroidManifest.xml since the delta visitor goes through the main - // folder before its children we can check when the path segment - // count is 2 (format will be /$Project/folder) and make sure we are - // processing res/, source folders or AndroidManifest.xml - - IResource resource = delta.getResource(); - IPath path = resource.getFullPath(); - String[] segments = path.segments(); - - // since the delta visitor also visits the root we return true if - // segments.length = 1 - if (segments.length == 1) { - return true; - } else if (segments.length == 2) { - // if we are at an item directly under the root directory, - // then we are not yet in a source or resource folder - mInRes = mInSrc = false; - - if (SdkConstants.FD_RESOURCES.equalsIgnoreCase(segments[1])) { - // this is the resource folder that was modified. we want to - // see its content. - - // since we're going to visit its children next, we set the - // flag - mInRes = true; - mInSrc = false; - return true; - } else if (AndroidConstants.FN_ANDROID_MANIFEST.equalsIgnoreCase(segments[1])) { - // any change in the manifest could trigger a new R.java - // class, so we don't need to check the delta kind - if (delta.getKind() != IResourceDelta.REMOVED) { - // parse the manifest for errors - AndroidManifestParser parser = BaseProjectHelper.parseManifestForError( - (IFile)resource, this); - - if (parser != null) { - mJavaPackage = parser.getPackage(); - } - - mCheckedManifestXml = true; - } - mCompileResources = true; - - // we don't want to go to the children, not like they are - // any for this resource anyway. - return false; - } else if (AndroidConstants.FN_PROJECT_AIDL.equalsIgnoreCase(segments[1])) { - // need to force recompilation of all the aidl files - mFullAidlCompilation = true; - } - } - - // at this point we can either be in the source folder or in the - // resource folder or in a different folder that contains a source - // folder. - // This is due to not all source folder being src/. Some could be - // something/somethingelse/src/ - - // so first we test if we already know we are in a source or - // resource folder. - - if (mInSrc) { - // if we are in the res folder, we are looking for the following changes: - // - added/removed/modified aidl files. - // - missing R.java file - - // if the resource is a folder, we just go straight to the children - if (resource.getType() == IResource.FOLDER) { - return true; - } - - if (resource.getType() != IResource.FILE) { - return false; - } - IFile file = (IFile)resource; - - // get the modification kind - int kind = delta.getKind(); - - if (kind == IResourceDelta.ADDED) { - // we only care about added files (inside the source folders), if they - // are aidl files. - - // get the extension of the resource - String ext = resource.getFileExtension(); - - if (AndroidConstants.EXT_AIDL.equalsIgnoreCase(ext)) { - // look for an already existing matching java file - String javaName = resource.getName().replaceAll( - AndroidConstants.RE_AIDL_EXT, - AndroidConstants.DOT_JAVA); - - // get the parent container - IContainer ic = resource.getParent(); - - IFile javaFile = ic.getFile(new Path(javaName)); - if (javaFile != null && javaFile.exists()) { - // check if that file was generated by the plugin. Normally those files are - // deleted automatically, but it's better to check. - String aidlPath = ProjectHelper.loadStringProperty(javaFile, - PreCompilerBuilder.PROPERTY_ANDROID_GENERATED); - if (aidlPath == null) { - // mark the aidl file that it cannot be compile just yet - ProjectHelper.saveBooleanProperty(file, - PreCompilerBuilder.PROPERTY_ANDROID_CONFLICT, true); - } - - // we add it anyway so that we can try to compile it at every compilation - // until the conflict is fixed. - mAidlToCompile.add(file); - - } else { - // the java file doesn't exist, we can safely add the file to the list - // of files to compile. - mAidlToCompile.add(file); - } - } - - return false; - } - - // get the filename - String fileName = segments[segments.length - 1]; - - boolean outputMessage = false; - - // Special case of R.java/Manifest.java. - // FIXME: This does not check the package. Any modification of R.java/Manifest.java in another project will trigger a new recompilation of the resources. - if (AndroidConstants.FN_RESOURCE_CLASS.equals(fileName) || - AndroidConstants.FN_MANIFEST_CLASS.equals(fileName)) { - // if it was removed, there's a possibility that it was removed due to a - // package change, or an aidl that was removed, but the only thing - // that will happen is that we'll have an extra build. Not much of a problem. - mCompileResources = true; - - // we want a warning - outputMessage = true; - } else { - - // get the extension of the resource - String ext = resource.getFileExtension(); - - if (AndroidConstants.EXT_AIDL.equalsIgnoreCase(ext)) { - if (kind == IResourceDelta.REMOVED) { - mAidlToRemove.add(file); - } else { - mAidlToCompile.add(file); - } - } else { - if (kind == IResourceDelta.REMOVED) { - // the file has been removed. we need to check it's a java file and that - // there's a matching aidl file. We can't check its persistent storage - // anymore. - if (AndroidConstants.EXT_JAVA.equalsIgnoreCase(ext)) { - String aidlFile = resource.getName().replaceAll( - AndroidConstants.RE_JAVA_EXT, - AndroidConstants.DOT_AIDL); - - // get the parent container - IContainer ic = resource.getParent(); - - IFile f = ic.getFile(new Path(aidlFile)); - if (f != null && f.exists() ) { - // make sure that the aidl file is not in conflict anymore, in - // case the java file was not generated by us. - if (ProjectHelper.loadBooleanProperty(f, - PreCompilerBuilder.PROPERTY_ANDROID_CONFLICT, false)) { - ProjectHelper.saveBooleanProperty(f, - PreCompilerBuilder.PROPERTY_ANDROID_CONFLICT, false); - } else { - outputMessage = true; - } - mAidlToCompile.add(f); - } - } - } else { - // check if it's an android generated java file. - IResource aidlSource = ProjectHelper.loadResourceProperty( - file, PreCompilerBuilder.PROPERTY_ANDROID_GENERATED); - - if (aidlSource != null && aidlSource.exists() && - aidlSource.getType() == IResource.FILE) { - // it looks like this was a java file created from an aidl file. - // we need to add the aidl file to the list of aidl file to compile - mAidlToCompile.add((IFile)aidlSource); - outputMessage = true; - } - } - } - } - - if (outputMessage) { - if (kind == IResourceDelta.REMOVED) { - // We pring an error just so that it's red, but it's just a warning really. - String msg = String.format(Messages.s_Removed_Recreating_s, fileName); - AdtPlugin.printErrorToConsole(mBuilder.getProject(), msg); - } else if (kind == IResourceDelta.CHANGED) { - // the file was modified manually! we can't allow it. - String msg = String.format(Messages.s_Modified_Manually_Recreating_s, fileName); - AdtPlugin.printErrorToConsole(mBuilder.getProject(), msg); - } - } - - // no children. - return false; - } else if (mInRes) { - // if we are in the res folder, we are looking for the following - // changes: - // - added/removed/modified xml files. - // - added/removed files of any other type - - // if the resource is a folder, we just go straight to the - // children - if (resource.getType() == IResource.FOLDER) { - return true; - } - - // get the extension of the resource - String ext = resource.getFileExtension(); - int kind = delta.getKind(); - - String p = resource.getProjectRelativePath().toString(); - String message = null; - switch (kind) { - case IResourceDelta.CHANGED: - // display verbose message - message = String.format(Messages.s_Modified_Recreating_s, p, - AndroidConstants.FN_RESOURCE_CLASS); - break; - case IResourceDelta.ADDED: - // display verbose message - message = String.format(Messages.Added_s_s_Needs_Updating, p, - AndroidConstants.FN_RESOURCE_CLASS); - break; - case IResourceDelta.REMOVED: - // display verbose message - message = String.format(Messages.s_Removed_s_Needs_Updating, p, - AndroidConstants.FN_RESOURCE_CLASS); - break; - } - if (message != null) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, - mBuilder.getProject(), message); - } - - if (AndroidConstants.EXT_XML.equalsIgnoreCase(ext)) { - if (kind != IResourceDelta.REMOVED) { - // check xml Validity - mBuilder.checkXML(resource, this); - } - - // if we are going through this resource, it was modified - // somehow. - // we don't care if it was an added/removed/changed event - mCompileResources = true; - return false; - } else { - // this is a non xml resource. - if (kind == IResourceDelta.ADDED - || kind == IResourceDelta.REMOVED) { - mCompileResources = true; - return false; - } - } - } else if (resource instanceof IFolder) { - // in this case we may be inside a folder that contains a source - // folder. - String[] sourceFolderSegments = findMatchingSourceFolder(mSourceFolders, segments); - if (sourceFolderSegments != null) { - // we have a match! - mInRes = false; - - // Check if the current folder is actually a source folder - if (sourceFolderSegments.length == segments.length) { - mInSrc = true; - } - - // and return true to visit the content, no matter what - return true; - } - - // if we're here, we are visiting another folder - // like /$Project/bin/ for instance (we get notified for changes - // in .class!) - // This could also be another source folder and we have found - // R.java in a previous source folder - // We don't want to visit its children - return false; - } - - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java deleted file mode 100644 index 19d7185..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2007 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.build; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.LoadStatus; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.sdklib.IAndroidTarget; - -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.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; - -import java.util.Map; - -/** - * Resource manager builder whose only purpose is to refresh the resource folder - * so that the other builder use an up to date version. - */ -public class ResourceManagerBuilder extends BaseBuilder { - - public static final String ID = "com.android.ide.eclipse.adt.ResourceManagerBuilder"; //$NON-NLS-1$ - - public ResourceManagerBuilder() { - super(); - } - - // build() returns a list of project from which this project depends for future compilation. - @SuppressWarnings("unchecked") //$NON-NLS-1$ - @Override - protected IProject[] build(int kind, Map args, IProgressMonitor monitor) - throws CoreException { - // Get the project. - IProject project = getProject(); - - // Clear the project of the generic markers - BaseBuilder.removeMarkersFromProject(project, AdtConstants.MARKER_ADT); - - // Check the compiler compliance level, displaying the error message - // since this is the first builder. - int res = ProjectHelper.checkCompilerCompliance(project); - String errorMessage = null; - switch (res) { - case ProjectHelper.COMPILER_COMPLIANCE_LEVEL: - errorMessage = Messages.Requires_Compiler_Compliance_5; - case ProjectHelper.COMPILER_COMPLIANCE_SOURCE: - errorMessage = Messages.Requires_Source_Compatibility_5; - case ProjectHelper.COMPILER_COMPLIANCE_CODEGEN_TARGET: - errorMessage = Messages.Requires_Class_Compatibility_5; - } - - if (errorMessage != null) { - BaseProjectHelper.addMarker(project, AdtConstants.MARKER_ADT, errorMessage, - IMarker.SEVERITY_ERROR); - AdtPlugin.printErrorToConsole(project, errorMessage); - - // interrupt the build. The next builders will not run. - stopBuild(errorMessage); - } - - // Check that the SDK directory has been setup. - String osSdkFolder = AdtPlugin.getOsSdkFolder(); - - if (osSdkFolder == null || osSdkFolder.length() == 0) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.No_SDK_Setup_Error); - markProject(AdtConstants.MARKER_ADT, Messages.No_SDK_Setup_Error, - IMarker.SEVERITY_ERROR); - - // This interrupts the build. The next builders will not run. - stopBuild(Messages.No_SDK_Setup_Error); - } - - // check if we have finished loading the SDK. - if (AdtPlugin.getDefault().getSdkLoadStatus() != LoadStatus.LOADED) { - // we exit silently - // This interrupts the build. The next builders will not run. - stopBuild("SDK is not loaded yet"); - } - - // check the project has a target - IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project); - if (projectTarget == null) { - // no target. marker has been set by the container initializer: exit silently. - // This interrupts the build. The next builders will not run. - stopBuild("Project has no target"); - } - - // Check the preference to be sure we are supposed to refresh - // the folders. - if (AdtPlugin.getAutoResRefresh()) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, - Messages.Refreshing_Res); - - // refresh the res folder. - IFolder resFolder = project.getFolder( - AndroidConstants.WS_RESOURCES); - resFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - - // Also refresh the assets folder to make sure the ApkBuilder - // will now it's changed and will force a new resource packaging. - IFolder assetsFolder = project.getFolder( - AndroidConstants.WS_ASSETS); - assetsFolder.refreshLocal(IResource.DEPTH_INFINITE, monitor); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/build_messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/build_messages.properties deleted file mode 100644 index 8ba43d4..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/build_messages.properties +++ /dev/null @@ -1,61 +0,0 @@ -Start_Full_Apk_Build=Starting full Package build. -Start_Full_Pre_Compiler=Starting full Pre Compiler. -Start_Inc_Apk_Build=Starting incremental Package build: Checking resource changes. -Start_Inc_Pre_Compiler=Starting incremental Pre Compiler: Checking resource changes. -Xml_Error=Error in an XML file: aborting build. -s_Missing_Repackaging=%1$s missing. Repackaging. -Project_Has_Errors=Project contains error(s). Package Builder aborted. -Failed_To_Get_Output=Failed to get project output folder\! -Output_Missing=Output folder missing\! Make sure your project is configured properly. -s_File_Missing=%1$s file missing\! -Unparsed_AAPT_Errors=Unparsed aapt error(s)\! Check the console for output. -Unparsed_AIDL_Errors=Unparsed aidl error\! Check the console for output. -AAPT_Exec_Error=Error executing aapt. Please check aapt is present at %1$s -Dalvik_Error_d=Conversion to Dalvik format failed with error %1$d -DX_Jar_Error=Dx.jar is not found inside the plugin. Reinstall ADT\! -Dalvik_Error_s=Conversion to Dalvik format failed: %1$s -Incompatible_VM_Warning=Note: You may be using an incompatible virtual machine or class library. -Requires_1_5_Error=This program requires JDK 1.5 compatibility. -Final_Archive_Error_s=Error generating final archive: %1$s -Marker_Delete_Error=Failed to delete marker '%1$s' for %2$s -Couldnt_Locate_s_Error=Could not locate '%1$s'. This will not be added to the package. -Compiler_Compliance_Error=Compiler compliance level not compatible: Build aborted. -No_SDK_Setup_Error=SDK directory has not been setup. Please go to the Android preferences and enter the location of the SDK. -s_Contains_Xml_Error=%1$s contains XML error: Build aborted. -s_Doesnt_Declare_Package_Error=%1$s does not declare a Java package: Build aborted. -Checking_Package_Change=Checking Java package value did not change... -Package_s_Doesnt_Exist_Error=Package '%1$s' does not exist\! -Preparing_Generated_Files=Preparing generated java files for update/creation. -AAPT_Error='aapt' error. Pre Compiler Build aborted. -Nothing_To_Compile=Nothing to pre compile\! -Removing_Generated_Classes=Removing generated java classes. -Delete_Obsolete_Error=Failed to delete obsolete %1$s, please delete it manually -DexWrapper_Dex_Loader=Dex Loader -AIDL_Java_Conflict=%1$s is in the way of %2$s, remove it or rename of one the files. -AIDL_Exec_Error=Error executing aidl. Please check aidl is present at %1$s -s_Removed_Recreating_s=%1$s was removed\! Recreating %1$s\! -s_Modified_Manually_Recreating_s=%1$s was modified manually\! Reverting to generated version\! -s_Modified_Recreating_s='%1$s' was modified, %2$s needs to be updated. -Added_s_s_Needs_Updating=New resource file: '%1$s', %2$s needs to be updated. -s_Removed_s_Needs_Updating='%1$s' was removed, %2$s needs to be updated. -Requires_Compiler_Compliance_5=Android requires compiler compliance level 5.0. Please fix project properties. -Requires_Source_Compatibility_5=Android requires source compatibility set to 5.0. Please fix project properties. -Requires_Class_Compatibility_5=Android requires .class compatibility set to 5.0. Please fix project properties. -Refreshing_Res=Refreshing resource folders. -DexWrapper_s_does_not_exists=%1$s does not exist or is not a file -DexWrapper_Failed_to_load_s=Failed to load %1$s -DexWrapper_Unable_To_Execute_Dex_s=Unable to execute dex: %1$s -DexWrapper_SecuryEx_Unable_To_Find_API=SecurityException: Unable to find API for dex.jar -DexWrapper_SecuryEx_Unable_To_Find_Method=SecurityException: Unable to find method for dex.jar -DexWrapper_SecuryEx_Unable_To_Find_Field=SecurityException: Unable to find field for dex.jar -ApkBuilder_UnableBuild_Dex_Not_loaded=Unable to build: the file dex.jar was not loaded from the SDK folder\! -ApkBuilder_Using_Default_Key=Using default debug key to sign package -ApkBuilder_Using_s_To_Sign=Using '%1$s' to sign package -ApkBuilder_Signing_Key_Creation_s=Signing Key Creation: -ApkBuilder_Unable_To_Gey_Key=Unable to get debug signature key -ApkBuilder_Certificate_Expired_on_s=Debug certificate expired on %1$s\! -ApkBuilder_Packaging_s=Packaging %1$s -ApkBuilder_JAVA_HOME_is_s=The Java VM Home used is: %1$s -ApkBuilder_Update_or_Execute_manually_s=Update it if necessary, or manually execute the following command: -ApkBuilder_s_Conflict_with_file_s=%1$s conflicts with another file already put at %2$s -ApkBuilder_Packaging_s_into_s=Packaging %1$s into %2$s diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunch.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunch.java deleted file mode 100644 index 3d60401..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunch.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.launching; - -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.ILaunchManager; -import org.eclipse.debug.core.Launch; -import org.eclipse.debug.core.model.ISourceLocator; - -/** - * Custom implementation of Launch to allow access to the LaunchManager - * - */ -class AndroidLaunch extends Launch { - - /** - * Basic constructor does nothing special - * @param launchConfiguration - * @param mode - * @param locator - */ - public AndroidLaunch(ILaunchConfiguration launchConfiguration, String mode, - ISourceLocator locator) { - super(launchConfiguration, mode, locator); - } - - /** Stops the launch, and removes it from the launch manager */ - public void stopLaunch() { - ILaunchManager mgr = getLaunchManager(); - - if (canTerminate()) { - try { - terminate(); - } catch (DebugException e) { - // well looks like we couldn't stop it. nothing else to be - // done really - } - } - // remove the launch - mgr.removeLaunch(this); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java deleted file mode 100644 index ac003df..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java +++ /dev/null @@ -1,1838 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.launching; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.Client; -import com.android.ddmlib.ClientData; -import com.android.ddmlib.Device; -import com.android.ddmlib.Log; -import com.android.ddmlib.MultiLineReceiver; -import com.android.ddmlib.SyncService; -import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; -import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; -import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; -import com.android.ddmlib.SyncService.SyncResult; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.debug.launching.DeviceChooserDialog.DeviceChooserResponse; -import com.android.ide.eclipse.adt.debug.ui.EmulatorConfigTab; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkManager; -import com.android.sdklib.avd.AvdManager; -import com.android.sdklib.avd.AvdManager.AvdInfo; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.ILaunchConfigurationType; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; -import org.eclipse.debug.core.ILaunchManager; -import org.eclipse.debug.core.model.IDebugTarget; -import org.eclipse.debug.ui.DebugUITools; -import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; -import org.eclipse.jdt.launching.IVMConnector; -import org.eclipse.jdt.launching.JavaRuntime; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Controls the launch of Android application either on a device or on the - * emulator. If an emulator is already running, this class will attempt to reuse - * it. - */ -public final class AndroidLaunchController implements IDebugBridgeChangeListener, - IDeviceChangeListener, IClientChangeListener { - - private static final String FLAG_AVD = "-avd"; //$NON-NLS-1$ - private static final String FLAG_NETDELAY = "-netdelay"; //$NON-NLS-1$ - private static final String FLAG_NETSPEED = "-netspeed"; //$NON-NLS-1$ - private static final String FLAG_WIPE_DATA = "-wipe-data"; //$NON-NLS-1$ - private static final String FLAG_NO_BOOT_ANIM = "-no-boot-anim"; //$NON-NLS-1$ - - private static final int MAX_ATTEMPT_COUNT = 5; - - private final static Pattern sAmErrorType = Pattern.compile("Error type (\\d+)"); //$NON-NLS-1$ - - /** - * A delayed launch waiting for a device to be present or ready before the - * application is launched. - */ - static final class DelayedLaunchInfo { - /** The device on which to launch the app */ - Device mDevice = null; - - /** The eclipse project */ - IProject mProject; - - /** Package name */ - String mPackageName; - - /** fully qualified name of the activity */ - String mActivity; - - /** IFile to the package (.apk) file */ - IFile mPackageFile; - - /** Debuggable attribute of the manifest file. */ - Boolean mDebuggable = null; - - /** Required ApiVersionNumber by the app. 0 means no requirements */ - int mRequiredApiVersionNumber = 0; - - InstallRetryMode mRetryMode = InstallRetryMode.NEVER; - - /** - * Launch action. See {@link LaunchConfigDelegate#ACTION_DEFAULT}, - * {@link LaunchConfigDelegate#ACTION_ACTIVITY}, - * {@link LaunchConfigDelegate#ACTION_DO_NOTHING} - */ - int mLaunchAction; - - /** the launch object */ - AndroidLaunch mLaunch; - - /** the monitor object */ - IProgressMonitor mMonitor; - - /** debug mode flag */ - boolean mDebugMode; - - int mAttemptCount = 0; - - boolean mCancelled = false; - - /** Basic constructor with activity and package info. */ - private DelayedLaunchInfo(IProject project, String packageName, String activity, - IFile pack, Boolean debuggable, int requiredApiVersionNumber, int launchAction, - AndroidLaunch launch, IProgressMonitor monitor) { - mProject = project; - mPackageName = packageName; - mActivity = activity; - mPackageFile = pack; - mLaunchAction = launchAction; - mLaunch = launch; - mMonitor = monitor; - mDebuggable = debuggable; - mRequiredApiVersionNumber = requiredApiVersionNumber; - } - } - - /** - * Map to store {@link ILaunchConfiguration} objects that must be launched as simple connection - * to running application. The integer is the port on which to connect. - * <b>ALL ACCESS MUST BE INSIDE A <code>synchronized (sListLock)</code> block!</b> - */ - private final static HashMap<ILaunchConfiguration, Integer> sRunningAppMap = - new HashMap<ILaunchConfiguration, Integer>(); - - private final static Object sListLock = sRunningAppMap; - - /** - * List of {@link DelayedLaunchInfo} waiting for an emulator to connect. - * <p>Once an emulator has connected, {@link DelayedLaunchInfo#mDevice} is set and the - * DelayedLaunchInfo object is moved to {@link AndroidLaunchController#mWaitingForReadyEmulatorList}. - * <b>ALL ACCESS MUST BE INSIDE A <code>synchronized (sListLock)</code> block!</b> - */ - private final ArrayList<DelayedLaunchInfo> mWaitingForEmulatorLaunches = - new ArrayList<DelayedLaunchInfo>(); - - /** - * List of application waiting to be launched on a device/emulator.<br> - * <b>ALL ACCESS MUST BE INSIDE A <code>synchronized (sListLock)</code> block!</b> - * */ - private final ArrayList<DelayedLaunchInfo> mWaitingForReadyEmulatorList = - new ArrayList<DelayedLaunchInfo>(); - - /** - * Application waiting to show up as waiting for debugger. - * <b>ALL ACCESS MUST BE INSIDE A <code>synchronized (sListLock)</code> block!</b> - */ - private final ArrayList<DelayedLaunchInfo> mWaitingForDebuggerApplications = - new ArrayList<DelayedLaunchInfo>(); - - /** - * List of clients that have appeared as waiting for debugger before their name was available. - * <b>ALL ACCESS MUST BE INSIDE A <code>synchronized (sListLock)</code> block!</b> - */ - private final ArrayList<Client> mUnknownClientsWaitingForDebugger = new ArrayList<Client>(); - - /** static instance for singleton */ - private static AndroidLaunchController sThis = new AndroidLaunchController(); - - enum InstallRetryMode { - NEVER, ALWAYS, PROMPT; - } - - /** - * Launch configuration data. This stores the result of querying the - * {@link ILaunchConfiguration} so that it's only done once. - */ - static final class AndroidLaunchConfiguration { - - /** - * Launch action. See {@link LaunchConfigDelegate#ACTION_DEFAULT}, - * {@link LaunchConfigDelegate#ACTION_ACTIVITY}, - * {@link LaunchConfigDelegate#ACTION_DO_NOTHING} - */ - public int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION; - - public static final boolean AUTO_TARGET_MODE = true; - - /** - * Target selection mode. - * <ul> - * <li><code>true</code>: automatic mode, see {@link #AUTO_TARGET_MODE}</li> - * <li><code>false</code>: manual mode</li> - * </ul> - */ - public boolean mTargetMode = LaunchConfigDelegate.DEFAULT_TARGET_MODE; - - /** - * Indicates whether the emulator should be called with -wipe-data - */ - public boolean mWipeData = LaunchConfigDelegate.DEFAULT_WIPE_DATA; - - /** - * Indicates whether the emulator should be called with -no-boot-anim - */ - public boolean mNoBootAnim = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM; - - /** - * AVD Name. - */ - public String mAvdName = null; - - public String mNetworkSpeed = EmulatorConfigTab.getSpeed( - LaunchConfigDelegate.DEFAULT_SPEED); - public String mNetworkDelay = EmulatorConfigTab.getDelay( - LaunchConfigDelegate.DEFAULT_DELAY); - - /** - * Optional custom command line parameter to launch the emulator - */ - public String mEmulatorCommandLine; - - /** - * Initialized the structure from an ILaunchConfiguration object. - * @param config - */ - public void set(ILaunchConfiguration config) { - try { - mLaunchAction = config.getAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, - mLaunchAction); - } catch (CoreException e1) { - // nothing to be done here, we'll use the default value - } - - try { - mTargetMode = config.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, - mTargetMode); - } catch (CoreException e) { - // nothing to be done here, we'll use the default value - } - - try { - mAvdName = config.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, mAvdName); - } catch (CoreException e) { - } - - int index = LaunchConfigDelegate.DEFAULT_SPEED; - try { - index = config.getAttribute(LaunchConfigDelegate.ATTR_SPEED, index); - } catch (CoreException e) { - // nothing to be done here, we'll use the default value - } - mNetworkSpeed = EmulatorConfigTab.getSpeed(index); - - index = LaunchConfigDelegate.DEFAULT_DELAY; - try { - index = config.getAttribute(LaunchConfigDelegate.ATTR_DELAY, index); - } catch (CoreException e) { - // nothing to be done here, we'll use the default value - } - mNetworkDelay = EmulatorConfigTab.getDelay(index); - - try { - mEmulatorCommandLine = config.getAttribute( - LaunchConfigDelegate.ATTR_COMMANDLINE, ""); //$NON-NLS-1$ - } catch (CoreException e) { - // lets not do anything here, we'll use the default value - } - - try { - mWipeData = config.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, mWipeData); - } catch (CoreException e) { - // nothing to be done here, we'll use the default value - } - - try { - mNoBootAnim = config.getAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, - mNoBootAnim); - } catch (CoreException e) { - // nothing to be done here, we'll use the default value - } - } - } - - /** - * Output receiver for am process (activity Manager); - */ - private final class AMReceiver extends MultiLineReceiver { - private DelayedLaunchInfo mLaunchInfo; - private Device mDevice; - - /** - * Basic constructor. - * @param launchInfo The launch info associated with the am process. - * @param device The device on which the launch is done. - */ - public AMReceiver(DelayedLaunchInfo launchInfo, Device device) { - mLaunchInfo = launchInfo; - mDevice = device; - } - - @Override - public void processNewLines(String[] lines) { - // first we check if one starts with error - ArrayList<String> array = new ArrayList<String>(); - boolean error = false; - boolean warning = false; - for (String s : lines) { - // ignore empty lines. - if (s.length() == 0) { - continue; - } - - // check for errors that output an error type, if the attempt count is still - // valid. If not the whole text will be output in the console - if (mLaunchInfo.mAttemptCount < MAX_ATTEMPT_COUNT && - mLaunchInfo.mCancelled == false) { - Matcher m = sAmErrorType.matcher(s); - if (m.matches()) { - // get the error type - int type = Integer.parseInt(m.group(1)); - - final int waitTime = 3; - String msg; - - switch (type) { - case 1: - /* Intended fall through */ - case 2: - msg = String.format( - "Device not ready. Waiting %1$d seconds before next attempt.", - waitTime); - break; - case 3: - msg = String.format( - "New package not yet registered with the system. Waiting %1$d seconds before next attempt.", - waitTime); - break; - default: - msg = String.format( - "Device not ready (%2$d). Waiting %1$d seconds before next attempt.", - waitTime, type); - break; - - } - - AdtPlugin.printToConsole(mLaunchInfo.mProject, msg); - - // launch another thread, that waits a bit and attempts another launch - new Thread("Delayed Launch attempt") { - @Override - public void run() { - try { - sleep(waitTime * 1000); - } catch (InterruptedException e) { - } - - launchApp(mLaunchInfo, mDevice); - } - }.start(); - - // no need to parse the rest - return; - } - } - - // check for error if needed - if (error == false && s.startsWith("Error:")) { //$NON-NLS-1$ - error = true; - } - if (warning == false && s.startsWith("Warning:")) { //$NON-NLS-1$ - warning = true; - } - - // add the line to the list - array.add("ActivityManager: " + s); //$NON-NLS-1$ - } - - // then we display them in the console - if (warning || error) { - AdtPlugin.printErrorToConsole(mLaunchInfo.mProject, array.toArray()); - } else { - AdtPlugin.printToConsole(mLaunchInfo.mProject, array.toArray()); - } - - // if error then we cancel the launch, and remove the delayed info - if (error) { - mLaunchInfo.mLaunch.stopLaunch(); - synchronized (sListLock) { - mWaitingForReadyEmulatorList.remove(mLaunchInfo); - } - } - } - - public boolean isCancelled() { - return false; - } - } - - /** - * Output receiver for "pm install package.apk" command line. - */ - private final static class InstallReceiver extends MultiLineReceiver { - - private final static String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$ - private final static Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$ - - private String mSuccess = null; - - public InstallReceiver() { - } - - @Override - public void processNewLines(String[] lines) { - for (String line : lines) { - if (line.length() > 0) { - if (line.startsWith(SUCCESS_OUTPUT)) { - mSuccess = null; - } else { - Matcher m = FAILURE_PATTERN.matcher(line); - if (m.matches()) { - mSuccess = m.group(1); - } - } - } - } - } - - public boolean isCancelled() { - return false; - } - - public String getSuccess() { - return mSuccess; - } - } - - - /** private constructor to enforce singleton */ - private AndroidLaunchController() { - AndroidDebugBridge.addDebugBridgeChangeListener(this); - AndroidDebugBridge.addDeviceChangeListener(this); - AndroidDebugBridge.addClientChangeListener(this); - } - - /** - * Returns the singleton reference. - */ - public static AndroidLaunchController getInstance() { - return sThis; - } - - - /** - * Launches a remote java debugging session on an already running application - * @param project The project of the application to debug. - * @param debugPort The port to connect the debugger to. - */ - public static void debugRunningApp(IProject project, int debugPort) { - // get an existing or new launch configuration - ILaunchConfiguration config = AndroidLaunchController.getLaunchConfig(project); - - if (config != null) { - setPortLaunchConfigAssociation(config, debugPort); - - // and launch - DebugUITools.launch(config, ILaunchManager.DEBUG_MODE); - } - } - - /** - * Returns an {@link ILaunchConfiguration} for the specified {@link IProject}. - * @param project the project - * @return a new or already existing <code>ILaunchConfiguration</code> or null if there was - * an error when creating a new one. - */ - public static ILaunchConfiguration getLaunchConfig(IProject project) { - // get the launch manager - ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); - - // now get the config type for our particular android type. - ILaunchConfigurationType configType = manager.getLaunchConfigurationType( - LaunchConfigDelegate.ANDROID_LAUNCH_TYPE_ID); - - String name = project.getName(); - - // search for an existing launch configuration - ILaunchConfiguration config = findConfig(manager, configType, name); - - // test if we found one or not - if (config == null) { - // Didn't find a matching config, so we make one. - // It'll be made in the "working copy" object first. - ILaunchConfigurationWorkingCopy wc = null; - - try { - // make the working copy object - wc = configType.newInstance(null, - manager.generateUniqueLaunchConfigurationNameFrom(name)); - - // set the project name - wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, name); - - // set the launch mode to default. - wc.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, - LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION); - - // set default target mode - wc.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, - LaunchConfigDelegate.DEFAULT_TARGET_MODE); - - // default AVD: None - wc.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null); - - // set the default network speed - wc.setAttribute(LaunchConfigDelegate.ATTR_SPEED, - LaunchConfigDelegate.DEFAULT_SPEED); - - // and delay - wc.setAttribute(LaunchConfigDelegate.ATTR_DELAY, - LaunchConfigDelegate.DEFAULT_DELAY); - - // default wipe data mode - wc.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, - LaunchConfigDelegate.DEFAULT_WIPE_DATA); - - // default disable boot animation option - wc.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, - LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM); - - // set default emulator options - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - String emuOptions = store.getString(AdtPlugin.PREFS_EMU_OPTIONS); - wc.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, emuOptions); - - // map the config and the project - wc.setMappedResources(getResourcesToMap(project)); - - // save the working copy to get the launch config object which we return. - return wc.doSave(); - - } catch (CoreException e) { - String msg = String.format( - "Failed to create a Launch config for project '%1$s': %2$s", - project.getName(), e.getMessage()); - AdtPlugin.printErrorToConsole(project, msg); - - // no launch! - return null; - } - } - - return config; - } - - /** - * Returns the list of resources to map to a Launch Configuration. - * @param project the project associated to the launch configuration. - */ - public static IResource[] getResourcesToMap(IProject project) { - ArrayList<IResource> array = new ArrayList<IResource>(2); - array.add(project); - - AndroidManifestHelper helper = new AndroidManifestHelper(project); - IFile manifest = helper.getManifestIFile(); - if (manifest != null) { - array.add(manifest); - } - - return array.toArray(new IResource[array.size()]); - } - - /** - * Launches an android app on the device or emulator - * - * @param project The project we're launching - * @param mode the mode in which to launch, one of the mode constants - * defined by <code>ILaunchManager</code> - <code>RUN_MODE</code> or - * <code>DEBUG_MODE</code>. - * @param apk the resource to the apk to launch. - * @param debuggable the debuggable value of the app, or null if not set. - * @param requiredApiVersionNumber the api version required by the app, or -1 if none. - * @param activity the class to provide to am to launch - * @param config the launch configuration - * @param launch the launch object - */ - public void launch(final IProject project, String mode, IFile apk, - String packageName, Boolean debuggable, int requiredApiVersionNumber, String activity, - final AndroidLaunchConfiguration config, final AndroidLaunch launch, - IProgressMonitor monitor) { - - String message; - if (config.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) { - message = String.format("Only Syncing Application Package"); - } else { - message = String.format("Launching: %1$s", activity); - } - AdtPlugin.printToConsole(project, message); - - // create the launch info - final DelayedLaunchInfo launchInfo = new DelayedLaunchInfo(project, packageName, - activity, apk, debuggable, requiredApiVersionNumber, config.mLaunchAction, - launch, monitor); - - // set the debug mode - launchInfo.mDebugMode = mode.equals(ILaunchManager.DEBUG_MODE); - - // get the SDK - Sdk currentSdk = Sdk.getCurrent(); - AvdManager avdManager = currentSdk.getAvdManager(); - - // get the project target - final IAndroidTarget projectTarget = currentSdk.getTarget(project); - - // FIXME: check errors on missing sdk, AVD manager, or project target. - - // device chooser response object. - final DeviceChooserResponse response = new DeviceChooserResponse(); - - /* - * Launch logic: - * - Manually Mode - * Always display a UI that lets a user see the current running emulators/devices. - * The UI must show which devices are compatibles, and allow launching new emulators - * with compatible (and not yet running) AVD. - * - Automatic Way - * * Preferred AVD set. - * If Preferred AVD is not running: launch it. - * Launch the application on the preferred AVD. - * * No preferred AVD. - * Count the number of compatible emulators/devices. - * If != 1, display a UI similar to manual mode. - * If == 1, launch the application on this AVD/device. - */ - - if (config.mTargetMode == AndroidLaunchConfiguration.AUTO_TARGET_MODE) { - // if we are in automatic target mode, we need to find the current devices - Device[] devices = AndroidDebugBridge.getBridge().getDevices(); - - // first check if we have a preferred AVD name, and if it actually exists, and is valid - // (ie able to run the project). - // We need to check this in case the AVD was recreated with a different target that is - // not compatible. - AvdInfo preferredAvd = null; - if (config.mAvdName != null) { - preferredAvd = avdManager.getAvd(config.mAvdName); - if (projectTarget.isCompatibleBaseFor(preferredAvd.getTarget()) == false) { - preferredAvd = null; - - AdtPlugin.printErrorToConsole(project, String.format( - "Preferred AVD '%1$s' is not compatible with the project target '%2$s'. Looking for a compatible AVD...", - config.mAvdName, projectTarget.getName())); - } - } - - if (preferredAvd != null) { - // look for a matching device - for (Device d : devices) { - String deviceAvd = d.getAvdName(); - if (deviceAvd != null && deviceAvd.equals(config.mAvdName)) { - response.setDeviceToUse(d); - - AdtPlugin.printToConsole(project, String.format( - "Automatic Target Mode: Preferred AVD '%1$s' is available on emulator '%2$s'", - config.mAvdName, d)); - - continueLaunch(response, project, launch, launchInfo, config); - return; - } - } - - // at this point we have a valid preferred AVD that is not running. - // We need to start it. - response.setAvdToLaunch(preferredAvd); - - AdtPlugin.printToConsole(project, String.format( - "Automatic Target Mode: Preferred AVD '%1$s' is not available. Launching new emulator.", - config.mAvdName)); - - continueLaunch(response, project, launch, launchInfo, config); - return; - } - - // no (valid) preferred AVD? look for one. - HashMap<Device, AvdInfo> compatibleRunningAvds = new HashMap<Device, AvdInfo>(); - boolean hasDevice = false; // if there's 1+ device running, we may force manual mode, - // as we cannot always detect proper compatibility with - // devices. This is the case if the project target is not - // a standard platform - for (Device d : devices) { - String deviceAvd = d.getAvdName(); - if (deviceAvd != null) { // physical devices return null. - AvdInfo info = avdManager.getAvd(deviceAvd); - if (info != null && projectTarget.isCompatibleBaseFor(info.getTarget())) { - compatibleRunningAvds.put(d, info); - } - } else { - if (projectTarget.isPlatform()) { // means this can run on any device as long - // as api level is high enough - String apiString = d.getProperty(SdkManager.PROP_VERSION_SDK); - try { - int apiNumber = Integer.parseInt(apiString); - if (apiNumber >= projectTarget.getApiVersionNumber()) { - // device is compatible with project - compatibleRunningAvds.put(d, null); - continue; - } - } catch (NumberFormatException e) { - // do nothing, we'll consider it a non compatible device below. - } - } - hasDevice = true; - } - } - - // depending on the number of devices, we'll simulate an automatic choice - // from the device chooser or simply show up the device chooser. - if (hasDevice == false && compatibleRunningAvds.size() == 0) { - // if zero emulators/devices, we launch an emulator. - // We need to figure out which AVD first. - - // we are going to take the closest AVD. ie a compatible AVD that has the API level - // closest to the project target. - AvdInfo[] avds = avdManager.getAvds(); - AvdInfo defaultAvd = null; - for (AvdInfo avd : avds) { - if (projectTarget.isCompatibleBaseFor(avd.getTarget())) { - if (defaultAvd == null || - avd.getTarget().getApiVersionNumber() < - defaultAvd.getTarget().getApiVersionNumber()) { - defaultAvd = avd; - } - } - } - - if (defaultAvd != null) { - response.setAvdToLaunch(defaultAvd); - - AdtPlugin.printToConsole(project, String.format( - "Automatic Target Mode: launching new emulator with compatible AVD '%1$s'", - defaultAvd.getName())); - - continueLaunch(response, project, launch, launchInfo, config); - return; - } else { - // FIXME: ask the user if he wants to create a AVD. - // we found no compatible AVD. - AdtPlugin.printErrorToConsole(project, String.format( - "Failed to find a AVD compatible with target '%1$s'. Launch aborted.", - projectTarget.getName())); - launch.stopLaunch(); - return; - } - } else if (hasDevice == false && compatibleRunningAvds.size() == 1) { - Entry<Device, AvdInfo> e = compatibleRunningAvds.entrySet().iterator().next(); - response.setDeviceToUse(e.getKey()); - - // get the AvdInfo, if null, the device is a physical device. - AvdInfo avdInfo = e.getValue(); - if (avdInfo != null) { - message = String.format("Automatic Target Mode: using existing emulator '%1$s' running compatible AVD '%2$s'", - response.getDeviceToUse(), e.getValue().getName()); - } else { - message = String.format("Automatic Target Mode: using device '%1$s'", - response.getDeviceToUse()); - } - AdtPlugin.printToConsole(project, message); - - continueLaunch(response, project, launch, launchInfo, config); - return; - } - - // if more than one device, we'll bring up the DeviceChooser dialog below. - if (compatibleRunningAvds.size() >= 2) { - message = "Automatic Target Mode: Several compatible targets. Please select a target device."; - } else if (hasDevice) { - message = "Automatic Target Mode: Unable to detect device compatibility. Please select a target device."; - } - - AdtPlugin.printToConsole(project, message); - } - - // bring up the device chooser. - AdtPlugin.getDisplay().asyncExec(new Runnable() { - public void run() { - try { - // open the chooser dialog. It'll fill 'response' with the device to use - // or the AVD to launch. - DeviceChooserDialog dialog = new DeviceChooserDialog( - AdtPlugin.getDisplay().getActiveShell(), - response, launchInfo.mPackageName, projectTarget); - if (dialog.open() == Dialog.OK) { - AndroidLaunchController.this.continueLaunch(response, project, launch, - launchInfo, config); - } else { - AdtPlugin.printErrorToConsole(project, "Launch canceled!"); - launch.stopLaunch(); - return; - } - } catch (Exception e) { - // there seems to be some case where the shell will be null. (might be - // an OS X bug). Because of this the creation of the dialog will throw - // and IllegalArg exception interrupting the launch with no user feedback. - // So we trap all the exception and display something. - String msg = e.getMessage(); - if (msg == null) { - msg = e.getClass().getCanonicalName(); - } - AdtPlugin.printErrorToConsole(project, - String.format("Error during launch: %s", msg)); - launch.stopLaunch(); - } - } - }); - } - - /** - * Continues the launch based on the DeviceChooser response. - * @param response the device chooser response - * @param project The project being launched - * @param launch The eclipse launch info - * @param launchInfo The {@link DelayedLaunchInfo} - * @param config The config needed to start a new emulator. - */ - void continueLaunch(final DeviceChooserResponse response, final IProject project, - final AndroidLaunch launch, final DelayedLaunchInfo launchInfo, - final AndroidLaunchConfiguration config) { - - // Since this is called from the UI thread we spawn a new thread - // to finish the launch. - new Thread() { - @Override - public void run() { - if (response.getAvdToLaunch() != null) { - // there was no selected device, we start a new emulator. - synchronized (sListLock) { - AvdInfo info = response.getAvdToLaunch(); - mWaitingForEmulatorLaunches.add(launchInfo); - AdtPlugin.printToConsole(project, String.format( - "Launching a new emulator with Virtual Device '%1$s'", - info.getName())); - boolean status = launchEmulator(config, info); - - if (status == false) { - // launching the emulator failed! - AdtPlugin.displayError("Emulator Launch", - "Couldn't launch the emulator! Make sure the SDK directory is properly setup and the emulator is not missing."); - - // stop the launch and return - mWaitingForEmulatorLaunches.remove(launchInfo); - AdtPlugin.printErrorToConsole(project, "Launch canceled!"); - launch.stopLaunch(); - return; - } - - return; - } - } else if (response.getDeviceToUse() != null) { - launchInfo.mDevice = response.getDeviceToUse(); - simpleLaunch(launchInfo, launchInfo.mDevice); - } - } - }.start(); - } - - /** - * Queries for a debugger port for a specific {@link ILaunchConfiguration}. - * <p/> - * If the configuration and a debugger port where added through - * {@link #setPortLaunchConfigAssociation(ILaunchConfiguration, int)}, then this method - * will return the debugger port, and remove the configuration from the list. - * @param launchConfig the {@link ILaunchConfiguration} - * @return the debugger port or {@link LaunchConfigDelegate#INVALID_DEBUG_PORT} if the - * configuration was not setup. - */ - static int getPortForConfig(ILaunchConfiguration launchConfig) { - synchronized (sListLock) { - Integer port = sRunningAppMap.get(launchConfig); - if (port != null) { - sRunningAppMap.remove(launchConfig); - return port; - } - } - - return LaunchConfigDelegate.INVALID_DEBUG_PORT; - } - - /** - * Set a {@link ILaunchConfiguration} and its associated debug port, in the list of - * launch config to connect directly to a running app instead of doing full launch (sync, - * launch, and connect to). - * @param launchConfig the {@link ILaunchConfiguration} object. - * @param port The debugger port to connect to. - */ - private static void setPortLaunchConfigAssociation(ILaunchConfiguration launchConfig, - int port) { - synchronized (sListLock) { - sRunningAppMap.put(launchConfig, port); - } - } - - /** - * Checks the build information, and returns whether the launch should continue. - * <p/>The value tested are: - * <ul> - * <li>Minimum API version requested by the application. If the target device does not match, - * the launch is canceled.</li> - * <li>Debuggable attribute of the application and whether or not the device requires it. If - * the device requires it and it is not set in the manifest, the launch will be forced to - * "release" mode instead of "debug"</li> - * <ul> - */ - private boolean checkBuildInfo(DelayedLaunchInfo launchInfo, Device device) { - if (device != null) { - // check the app required API level versus the target device API level - - String deviceApiVersionName = device.getProperty(Device.PROP_BUILD_VERSION); - String value = device.getProperty(Device.PROP_BUILD_VERSION_NUMBER); - int deviceApiVersionNumber = 0; - try { - deviceApiVersionNumber = Integer.parseInt(value); - } catch (NumberFormatException e) { - // pass, we'll keep the deviceVersionNumber value at 0. - } - - if (launchInfo.mRequiredApiVersionNumber == 0) { - // warn the API level requirement is not set. - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "WARNING: Application does not specify an API level requirement!"); - - // and display the target device API level (if known) - if (deviceApiVersionName == null || deviceApiVersionNumber == 0) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "WARNING: Unknown device API version!"); - } else { - AdtPlugin.printErrorToConsole(launchInfo.mProject, String.format( - "Device API version is %1$d (Android %2$s)", deviceApiVersionNumber, - deviceApiVersionName)); - } - } else { // app requires a specific API level - if (deviceApiVersionName == null || deviceApiVersionNumber == 0) { - AdtPlugin.printToConsole(launchInfo.mProject, - "WARNING: Unknown device API version!"); - } else if (deviceApiVersionNumber < launchInfo.mRequiredApiVersionNumber) { - String msg = String.format( - "ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).", - launchInfo.mRequiredApiVersionNumber, deviceApiVersionNumber, - deviceApiVersionName); - AdtPlugin.printErrorToConsole(launchInfo.mProject, msg); - - // abort the launch - return false; - } - } - - // now checks that the device/app can be debugged (if needed) - if (device.isEmulator() == false && launchInfo.mDebugMode) { - String debuggableDevice = device.getProperty(Device.PROP_DEBUGGABLE); - if (debuggableDevice != null && debuggableDevice.equals("0")) { //$NON-NLS-1$ - // the device is "secure" and requires apps to declare themselves as debuggable! - if (launchInfo.mDebuggable == null) { - String message1 = String.format( - "Device '%1$s' requires that applications explicitely declare themselves as debuggable in their manifest.", - device.getSerialNumber()); - String message2 = String.format("Application '%1$s' does not have the attribute 'debuggable' set to TRUE in its manifest and cannot be debugged.", - launchInfo.mPackageName); - AdtPlugin.printErrorToConsole(launchInfo.mProject, message1, message2); - - // because am -D does not check for ro.debuggable and the - // 'debuggable' attribute, it is important we do not use the -D option - // in this case or the app will wait for a debugger forever and never - // really launch. - launchInfo.mDebugMode = false; - } else if (launchInfo.mDebuggable == Boolean.FALSE) { - String message = String.format("Application '%1$s' has its 'debuggable' attribute set to FALSE and cannot be debugged.", - launchInfo.mPackageName); - AdtPlugin.printErrorToConsole(launchInfo.mProject, message); - - // because am -D does not check for ro.debuggable and the - // 'debuggable' attribute, it is important we do not use the -D option - // in this case or the app will wait for a debugger forever and never - // really launch. - launchInfo.mDebugMode = false; - } - } - } - } - - return true; - } - - /** - * Do a simple launch on the specified device, attempting to sync the new - * package, and then launching the application. Failed sync/launch will - * stop the current AndroidLaunch and return false; - * @param launchInfo - * @param device - * @return true if succeed - */ - private boolean simpleLaunch(DelayedLaunchInfo launchInfo, Device device) { - // API level check - if (checkBuildInfo(launchInfo, device) == false) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, "Launch canceled!"); - launchInfo.mLaunch.stopLaunch(); - return false; - } - - // sync the app - if (syncApp(launchInfo, device) == false) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, "Launch canceled!"); - launchInfo.mLaunch.stopLaunch(); - return false; - } - - // launch the app - launchApp(launchInfo, device); - - return true; - } - - - /** - * Syncs the application on the device/emulator. - * - * @param launchInfo The Launch information object. - * @param device the device on which to sync the application - * @return true if the install succeeded. - */ - private boolean syncApp(DelayedLaunchInfo launchInfo, Device device) { - SyncService sync = device.getSyncService(); - if (sync != null) { - IPath path = launchInfo.mPackageFile.getLocation(); - String message = String.format("Uploading %1$s onto device '%2$s'", - path.lastSegment(), device.getSerialNumber()); - AdtPlugin.printToConsole(launchInfo.mProject, message); - - String osLocalPath = path.toOSString(); - String apkName = launchInfo.mPackageFile.getName(); - String remotePath = "/data/local/tmp/" + apkName; //$NON-NLS-1$ - - SyncResult result = sync.pushFile(osLocalPath, remotePath, - SyncService.getNullProgressMonitor()); - - if (result.getCode() != SyncService.RESULT_OK) { - String msg = String.format("Failed to upload %1$s on '%2$s': %3$s", - apkName, device.getSerialNumber(), result.getMessage()); - AdtPlugin.printErrorToConsole(launchInfo.mProject, msg); - return false; - } - - // Now that the package is uploaded, we can install it properly. - // This will check that there isn't another apk declaring the same package, or - // that another install used a different key. - boolean installResult = installPackage(launchInfo, remotePath, device); - - // now we delete the app we sync'ed - try { - device.executeShellCommand("rm " + remotePath, new MultiLineReceiver() { //$NON-NLS-1$ - @Override - public void processNewLines(String[] lines) { - // pass - } - public boolean isCancelled() { - return false; - } - }); - } catch (IOException e) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, String.format( - "Failed to delete temporary package: %1$s", e.getMessage())); - return false; - } - - return installResult; - } - - String msg = String.format( - "Failed to upload %1$s on device '%2$s': Unable to open sync connection!", - launchInfo.mPackageFile.getName(), device.getSerialNumber()); - AdtPlugin.printErrorToConsole(launchInfo.mProject, msg); - - return false; - } - - /** - * Installs the application package that was pushed to a temporary location on the device. - * @param launchInfo The launch information - * @param remotePath The remote path of the package. - * @param device The device on which the launch is done. - */ - private boolean installPackage(DelayedLaunchInfo launchInfo, final String remotePath, - final Device device) { - - String message = String.format("Installing %1$s...", launchInfo.mPackageFile.getName()); - AdtPlugin.printToConsole(launchInfo.mProject, message); - - try { - String result = doInstall(launchInfo, remotePath, device, false /* reinstall */); - - /* For now we force to retry the install (after uninstalling) because there's no - * other way around it: adb install does not want to update a package w/o uninstalling - * the old one first! - */ - return checkInstallResult(result, device, launchInfo, remotePath, - InstallRetryMode.ALWAYS); - } catch (IOException e) { - // do nothing, we'll return false - } - - return false; - } - - /** - * Checks the result of an installation, and takes optional actions based on it. - * @param result the result string from the installation - * @param device the device on which the installation occured. - * @param launchInfo the {@link DelayedLaunchInfo} - * @param remotePath the temporary path of the package on the device - * @param retryMode indicates what to do in case, a package already exists. - * @return <code>true<code> if success, <code>false</code> otherwise. - * @throws IOException - */ - private boolean checkInstallResult(String result, Device device, DelayedLaunchInfo launchInfo, - String remotePath, InstallRetryMode retryMode) throws IOException { - if (result == null) { - AdtPlugin.printToConsole(launchInfo.mProject, "Success!"); - return true; - } else if (result.equals("INSTALL_FAILED_ALREADY_EXISTS")) { //$NON-NLS-1$ - if (retryMode == InstallRetryMode.PROMPT) { - boolean prompt = AdtPlugin.displayPrompt("Application Install", - "A previous installation needs to be uninstalled before the new package can be installed.\nDo you want to uninstall?"); - if (prompt) { - retryMode = InstallRetryMode.ALWAYS; - } else { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Installation error! The package already exists."); - return false; - } - } - - if (retryMode == InstallRetryMode.ALWAYS) { - /* - * TODO: create a UI that gives the dev the choice to: - * - clean uninstall on launch - * - full uninstall if application exists. - * - soft uninstall if application exists (keeps the app data around). - * - always ask (choice of soft-reinstall, full reinstall) - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Application already exists, uninstalling..."); - String res = doUninstall(device, launchInfo); - if (res == null) { - AdtPlugin.printToConsole(launchInfo.mProject, "Success!"); - } else { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format("Failed to uninstall: %1$s", res)); - return false; - } - */ - - AdtPlugin.printToConsole(launchInfo.mProject, - "Application already exists. Attempting to re-install instead..."); - String res = doInstall(launchInfo, remotePath, device, true /* reinstall */); - return checkInstallResult(res, device, launchInfo, remotePath, - InstallRetryMode.NEVER); - } - - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Installation error! The package already exists."); - } else if (result.equals("INSTALL_FAILED_INVALID_APK")) { //$NON-NLS-1$ - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Installation failed due to invalid APK file!", - "Please check logcat output for more details."); - } else if (result.equals("INSTALL_FAILED_INVALID_URI")) { //$NON-NLS-1$ - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Installation failed due to invalid URI!", - "Please check logcat output for more details."); - } else if (result.equals("INSTALL_FAILED_COULDNT_COPY")) { //$NON-NLS-1$ - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format("Installation failed: Could not copy %1$s to its final location!", - launchInfo.mPackageFile.getName()), - "Please check logcat output for more details."); - } else if (result.equals("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES")) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Re-installation failed due to different application signatures.", - "You must perform a full uninstall of the application. WARNING: This will remove the application data!", - String.format("Please execute 'adb uninstall %1$s' in a shell.", launchInfo.mPackageName)); - } else { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format("Installation error: %1$s", result), - "Please check logcat output for more details."); - } - - return false; - } - - /** - * Performs the uninstallation of an application. - * @param device the device on which to install the application. - * @param launchInfo the {@link DelayedLaunchInfo}. - * @return a {@link String} with an error code, or <code>null</code> if success. - * @throws IOException - */ - @SuppressWarnings("unused") - private String doUninstall(Device device, DelayedLaunchInfo launchInfo) throws IOException { - InstallReceiver receiver = new InstallReceiver(); - try { - device.executeShellCommand("pm uninstall " + launchInfo.mPackageName, //$NON-NLS-1$ - receiver); - } catch (IOException e) { - String msg = String.format( - "Failed to uninstall %1$s: %2$s", launchInfo.mPackageName, e.getMessage()); - AdtPlugin.printErrorToConsole(launchInfo.mProject, msg); - throw e; - } - - return receiver.getSuccess(); - } - - /** - * Performs the installation of an application whose package has been uploaded on the device. - * <p/>Before doing it, if the application is already running on the device, it is killed. - * @param launchInfo the {@link DelayedLaunchInfo}. - * @param remotePath the path of the application package in the device tmp folder. - * @param device the device on which to install the application. - * @param reinstall - * @return a {@link String} with an error code, or <code>null</code> if success. - * @throws IOException - */ - private String doInstall(DelayedLaunchInfo launchInfo, final String remotePath, - final Device device, boolean reinstall) throws IOException { - // kill running application - Client application = device.getClient(launchInfo.mPackageName); - if (application != null) { - application.kill(); - } - - InstallReceiver receiver = new InstallReceiver(); - try { - String cmd = String.format( - reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"", //$NON-NLS-1$ //$NON-NLS-2$ - remotePath); //$NON-NLS-1$ //$NON-NLS-2$ - device.executeShellCommand(cmd, receiver); - } catch (IOException e) { - String msg = String.format( - "Failed to install %1$s on device '%2$s': %3$s", - launchInfo.mPackageFile.getName(), device.getSerialNumber(), e.getMessage()); - AdtPlugin.printErrorToConsole(launchInfo.mProject, msg); - throw e; - } - - return receiver.getSuccess(); - } - - /** - * launches an application on a device or emulator - * - * @param info the {@link DelayedLaunchInfo} that indicates the activity to launch - * @param device the device or emulator to launch the application on - */ - private void launchApp(final DelayedLaunchInfo info, Device device) { - // if we're not supposed to do anything, just stop the Launch item and return; - if (info.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) { - String msg = String.format("%1$s installed on device", - info.mPackageFile.getFullPath().toOSString()); - AdtPlugin.printToConsole(info.mProject, msg, "Done!"); - info.mLaunch.stopLaunch(); - return; - } - try { - String msg = String.format("Starting activity %1$s on device ", info.mActivity, - info.mDevice); - AdtPlugin.printToConsole(info.mProject, msg); - - // In debug mode, we need to add the info to the list of application monitoring - // client changes. - if (info.mDebugMode) { - synchronized (sListLock) { - if (mWaitingForDebuggerApplications.contains(info) == false) { - mWaitingForDebuggerApplications.add(info); - } - } - } - - // increment launch attempt count, to handle retries and timeouts - info.mAttemptCount++; - - // now we actually launch the app. - device.executeShellCommand("am start" //$NON-NLS-1$ - + (info.mDebugMode ? " -D" //$NON-NLS-1$ - : "") //$NON-NLS-1$ - + " -n " //$NON-NLS-1$ - + info.mPackageName + "/" //$NON-NLS-1$ - + info.mActivity.replaceAll("\\$", "\\\\\\$"), //$NON-NLS-1$ //$NON-NLS-2$ - new AMReceiver(info, device)); - - // if the app is not a debug app, we need to do some clean up, as - // the process is done! - if (info.mDebugMode == false) { - // stop the launch object, since there's no debug, and it can't - // provide any control over the app - info.mLaunch.stopLaunch(); - } - } catch (IOException e) { - // something went wrong trying to launch the app. - // lets stop the Launch - AdtPlugin.printErrorToConsole(info.mProject, - String.format("Launch error: %s", e.getMessage())); - info.mLaunch.stopLaunch(); - - // and remove it from the list of app waiting for debuggers - synchronized (sListLock) { - mWaitingForDebuggerApplications.remove(info); - } - } - } - - private boolean launchEmulator(AndroidLaunchConfiguration config, AvdInfo avdToLaunch) { - - // split the custom command line in segments - ArrayList<String> customArgs = new ArrayList<String>(); - boolean has_wipe_data = false; - if (config.mEmulatorCommandLine != null && config.mEmulatorCommandLine.length() > 0) { - String[] segments = config.mEmulatorCommandLine.split("\\s+"); //$NON-NLS-1$ - - // we need to remove the empty strings - for (String s : segments) { - if (s.length() > 0) { - customArgs.add(s); - if (!has_wipe_data && s.equals(FLAG_WIPE_DATA)) { - has_wipe_data = true; - } - } - } - } - - boolean needs_wipe_data = config.mWipeData && !has_wipe_data; - if (needs_wipe_data) { - if (!AdtPlugin.displayPrompt("Android Launch", "Are you sure you want to wipe all user data when starting this emulator?")) { - needs_wipe_data = false; - } - } - - // build the command line based on the available parameters. - ArrayList<String> list = new ArrayList<String>(); - - list.add(AdtPlugin.getOsAbsoluteEmulator()); - list.add(FLAG_AVD); - list.add(avdToLaunch.getName()); - - if (config.mNetworkSpeed != null) { - list.add(FLAG_NETSPEED); - list.add(config.mNetworkSpeed); - } - - if (config.mNetworkDelay != null) { - list.add(FLAG_NETDELAY); - list.add(config.mNetworkDelay); - } - - if (needs_wipe_data) { - list.add(FLAG_WIPE_DATA); - } - - if (config.mNoBootAnim) { - list.add(FLAG_NO_BOOT_ANIM); - } - - list.addAll(customArgs); - - // convert the list into an array for the call to exec. - String[] command = list.toArray(new String[list.size()]); - - // launch the emulator - try { - Process process = Runtime.getRuntime().exec(command); - grabEmulatorOutput(process); - } catch (IOException e) { - return false; - } - - return true; - } - - /** - * Looks for and returns an existing {@link ILaunchConfiguration} object for a - * specified project. - * @param manager The {@link ILaunchManager}. - * @param type The {@link ILaunchConfigurationType}. - * @param projectName The name of the project - * @return an existing <code>ILaunchConfiguration</code> object matching the project, or - * <code>null</code>. - */ - private static ILaunchConfiguration findConfig(ILaunchManager manager, - ILaunchConfigurationType type, String projectName) { - try { - ILaunchConfiguration[] configs = manager.getLaunchConfigurations(type); - - for (ILaunchConfiguration config : configs) { - if (config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, - "").equals(projectName)) { //$NON-NLS-1$ - return config; - } - } - } catch (CoreException e) { - MessageDialog.openError(AdtPlugin.getDisplay().getActiveShell(), - "Launch Error", e.getStatus().getMessage()); - } - - // didn't find anything that matches. Return null - return null; - - } - - - /** - * Connects a remote debugger on the specified port. - * @param debugPort The port to connect the debugger to - * @param launch The associated AndroidLaunch object. - * @param monitor A Progress monitor - * @return false if cancelled by the monitor - * @throws CoreException - */ - public static boolean connectRemoteDebugger(int debugPort, - AndroidLaunch launch, IProgressMonitor monitor) - throws CoreException { - // get some default parameters. - int connectTimeout = JavaRuntime.getPreferences().getInt(JavaRuntime.PREF_CONNECT_TIMEOUT); - - HashMap<String, String> newMap = new HashMap<String, String>(); - - newMap.put("hostname", "localhost"); //$NON-NLS-1$ //$NON-NLS-2$ - - newMap.put("port", Integer.toString(debugPort)); //$NON-NLS-1$ - - newMap.put("timeout", Integer.toString(connectTimeout)); - - // get the default VM connector - IVMConnector connector = JavaRuntime.getDefaultVMConnector(); - - // connect to remote VM - connector.connect(newMap, monitor, launch); - - // check for cancellation - if (monitor.isCanceled()) { - IDebugTarget[] debugTargets = launch.getDebugTargets(); - for (IDebugTarget target : debugTargets) { - if (target.canDisconnect()) { - target.disconnect(); - } - } - return false; - } - - return true; - } - - /** - * Launch a new thread that connects a remote debugger on the specified port. - * @param debugPort The port to connect the debugger to - * @param androidLaunch The associated AndroidLaunch object. - * @param monitor A Progress monitor - * @see #connectRemoteDebugger(int, AndroidLaunch, IProgressMonitor) - */ - public static void launchRemoteDebugger( final int debugPort, final AndroidLaunch androidLaunch, - final IProgressMonitor monitor) { - new Thread("Debugger connection") { //$NON-NLS-1$ - @Override - public void run() { - try { - connectRemoteDebugger(debugPort, androidLaunch, monitor); - } catch (CoreException e) { - androidLaunch.stopLaunch(); - } - monitor.done(); - } - }.start(); - } - - /** - * Sent when a new {@link AndroidDebugBridge} is started. - * <p/> - * This is sent from a non UI thread. - * @param bridge the new {@link AndroidDebugBridge} object. - * - * @see IDebugBridgeChangeListener#bridgeChanged(AndroidDebugBridge) - */ - public void bridgeChanged(AndroidDebugBridge bridge) { - // The adb server has changed. We cancel any pending launches. - String message1 = "adb server change: cancelling '%1$s' launch!"; - String message2 = "adb server change: cancelling sync!"; - synchronized (sListLock) { - for (DelayedLaunchInfo launchInfo : mWaitingForReadyEmulatorList) { - if (launchInfo.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, message2); - } else { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format(message1, launchInfo.mActivity)); - } - launchInfo.mLaunch.stopLaunch(); - } - for (DelayedLaunchInfo launchInfo : mWaitingForDebuggerApplications) { - if (launchInfo.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, message2); - } else { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format(message1, launchInfo.mActivity)); - } - launchInfo.mLaunch.stopLaunch(); - } - - mWaitingForReadyEmulatorList.clear(); - mWaitingForDebuggerApplications.clear(); - } - } - - /** - * Sent when the a device is connected to the {@link AndroidDebugBridge}. - * <p/> - * This is sent from a non UI thread. - * @param device the new device. - * - * @see IDeviceChangeListener#deviceConnected(Device) - */ - public void deviceConnected(Device device) { - synchronized (sListLock) { - // look if there's an app waiting for a device - if (mWaitingForEmulatorLaunches.size() > 0) { - // get/remove first launch item from the list - // FIXME: what if we have multiple launches waiting? - DelayedLaunchInfo launchInfo = mWaitingForEmulatorLaunches.get(0); - mWaitingForEmulatorLaunches.remove(0); - - // give the launch item its device for later use. - launchInfo.mDevice = device; - - // and move it to the other list - mWaitingForReadyEmulatorList.add(launchInfo); - - // and tell the user about it - AdtPlugin.printToConsole(launchInfo.mProject, - String.format("New emulator found: %1$s", device.getSerialNumber())); - AdtPlugin.printToConsole(launchInfo.mProject, - String.format("Waiting for HOME ('%1$s') to be launched...", - AdtPlugin.getDefault().getPreferenceStore().getString( - AdtPlugin.PREFS_HOME_PACKAGE))); - } - } - } - - /** - * Sent when the a device is connected to the {@link AndroidDebugBridge}. - * <p/> - * This is sent from a non UI thread. - * @param device the new device. - * - * @see IDeviceChangeListener#deviceDisconnected(Device) - */ - @SuppressWarnings("unchecked") - public void deviceDisconnected(Device device) { - // any pending launch on this device must be canceled. - String message = "%1$s disconnected! Cancelling '%2$s' launch!"; - synchronized (sListLock) { - ArrayList<DelayedLaunchInfo> copyList = - (ArrayList<DelayedLaunchInfo>)mWaitingForReadyEmulatorList.clone(); - for (DelayedLaunchInfo launchInfo : copyList) { - if (launchInfo.mDevice == device) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format(message, device.getSerialNumber(), launchInfo.mActivity)); - launchInfo.mLaunch.stopLaunch(); - mWaitingForReadyEmulatorList.remove(launchInfo); - } - } - copyList = (ArrayList<DelayedLaunchInfo>)mWaitingForDebuggerApplications.clone(); - for (DelayedLaunchInfo launchInfo : copyList) { - if (launchInfo.mDevice == device) { - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format(message, device.getSerialNumber(), launchInfo.mActivity)); - launchInfo.mLaunch.stopLaunch(); - mWaitingForDebuggerApplications.remove(launchInfo); - } - } - } - } - - /** - * Sent when a device data changed, or when clients are started/terminated on the device. - * <p/> - * This is sent from a non UI thread. - * @param device the device that was updated. - * @param changeMask the mask indicating what changed. - * - * @see IDeviceChangeListener#deviceChanged(Device, int) - */ - public void deviceChanged(Device device, int changeMask) { - // We could check if any starting device we care about is now ready, but we can wait for - // its home app to show up, so... - } - - /** - * Sent when an existing client information changed. - * <p/> - * This is sent from a non UI thread. - * @param client the updated client. - * @param changeMask the bit mask describing the changed properties. It can contain - * any of the following values: {@link Client#CHANGE_INFO}, {@link Client#CHANGE_NAME} - * {@link Client#CHANGE_DEBUGGER_INTEREST}, {@link Client#CHANGE_THREAD_MODE}, - * {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, - * {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA} - * - * @see IClientChangeListener#clientChanged(Client, int) - */ - public void clientChanged(final Client client, int changeMask) { - boolean connectDebugger = false; - if ((changeMask & Client.CHANGE_NAME) == Client.CHANGE_NAME) { - String applicationName = client.getClientData().getClientDescription(); - if (applicationName != null) { - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - String home = store.getString(AdtPlugin.PREFS_HOME_PACKAGE); - - if (home.equals(applicationName)) { - - // looks like home is up, get its device - Device device = client.getDevice(); - - // look for application waiting for home - synchronized (sListLock) { - for (int i = 0 ; i < mWaitingForReadyEmulatorList.size() ;) { - DelayedLaunchInfo launchInfo = mWaitingForReadyEmulatorList.get(i); - if (launchInfo.mDevice == device) { - // it's match, remove from the list - mWaitingForReadyEmulatorList.remove(i); - - // We couldn't check earlier the API level of the device - // (it's asynchronous when the device boot, and usually - // deviceConnected is called before it's queried for its build info) - // so we check now - if (checkBuildInfo(launchInfo, device) == false) { - // device is not the proper API! - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Launch canceled!"); - launchInfo.mLaunch.stopLaunch(); - return; - } - - AdtPlugin.printToConsole(launchInfo.mProject, - String.format("HOME is up on device '%1$s'", - device.getSerialNumber())); - - // attempt to sync the new package onto the device. - if (syncApp(launchInfo, device)) { - // application package is sync'ed, lets attempt to launch it. - launchApp(launchInfo, device); - } else { - // failure! Cancel and return - AdtPlugin.printErrorToConsole(launchInfo.mProject, - "Launch canceled!"); - launchInfo.mLaunch.stopLaunch(); - } - - break; - } else { - i++; - } - } - } - } - - // check if it's already waiting for a debugger, and if so we connect to it. - if (client.getClientData().getDebuggerConnectionStatus() == ClientData.DEBUGGER_WAITING) { - // search for this client in the list; - synchronized (sListLock) { - int index = mUnknownClientsWaitingForDebugger.indexOf(client); - if (index != -1) { - connectDebugger = true; - mUnknownClientsWaitingForDebugger.remove(client); - } - } - } - } - } - - // if it's not home, it could be an app that is now in debugger mode that we're waiting for - // lets check it - - if ((changeMask & Client.CHANGE_DEBUGGER_INTEREST) == Client.CHANGE_DEBUGGER_INTEREST) { - ClientData clientData = client.getClientData(); - String applicationName = client.getClientData().getClientDescription(); - if (clientData.getDebuggerConnectionStatus() == ClientData.DEBUGGER_WAITING) { - // Get the application name, and make sure its valid. - if (applicationName == null) { - // looks like we don't have the client yet, so we keep it around for when its - // name becomes available. - synchronized (sListLock) { - mUnknownClientsWaitingForDebugger.add(client); - } - return; - } else { - connectDebugger = true; - } - } - } - - if (connectDebugger) { - Log.d("adt", "Debugging " + client); - // now check it against the apps waiting for a debugger - String applicationName = client.getClientData().getClientDescription(); - Log.d("adt", "App Name: " + applicationName); - synchronized (sListLock) { - for (int i = 0 ; i < mWaitingForDebuggerApplications.size() ;) { - final DelayedLaunchInfo launchInfo = mWaitingForDebuggerApplications.get(i); - if (client.getDevice() == launchInfo.mDevice && - applicationName.equals(launchInfo.mPackageName)) { - // this is a match. We remove the launch info from the list - mWaitingForDebuggerApplications.remove(i); - - // and connect the debugger. - String msg = String.format( - "Attempting to connect debugger to '%1$s' on port %2$d", - launchInfo.mPackageName, client.getDebuggerListenPort()); - AdtPlugin.printToConsole(launchInfo.mProject, msg); - - new Thread("Debugger Connection") { //$NON-NLS-1$ - @Override - public void run() { - try { - if (connectRemoteDebugger( - client.getDebuggerListenPort(), - launchInfo.mLaunch, launchInfo.mMonitor) == false) { - return; - } - } catch (CoreException e) { - // well something went wrong. - AdtPlugin.printErrorToConsole(launchInfo.mProject, - String.format("Launch error: %s", e.getMessage())); - // stop the launch - launchInfo.mLaunch.stopLaunch(); - } - - launchInfo.mMonitor.done(); - } - }.start(); - - // we're done processing this client. - return; - - } else { - i++; - } - } - } - - // if we get here, we haven't found an app that we were launching, so we look - // for opened android projects that contains the app asking for a debugger. - // If we find one, we automatically connect to it. - IProject project = ProjectHelper.findAndroidProjectByAppName(applicationName); - - if (project != null) { - debugRunningApp(project, client.getDebuggerListenPort()); - } - } - } - - /** - * Get the stderr/stdout outputs of a process and return when the process is done. - * Both <b>must</b> be read or the process will block on windows. - * @param process The process to get the ouput from - */ - private void grabEmulatorOutput(final Process process) { - // read the lines as they come. if null is returned, it's - // because the process finished - new Thread("") { //$NON-NLS-1$ - @Override - public void run() { - // create a buffer to read the stderr output - InputStreamReader is = new InputStreamReader(process.getErrorStream()); - BufferedReader errReader = new BufferedReader(is); - - try { - while (true) { - String line = errReader.readLine(); - if (line != null) { - AdtPlugin.printErrorToConsole("Emulator", line); - } else { - break; - } - } - } catch (IOException e) { - // do nothing. - } - } - }.start(); - - new Thread("") { //$NON-NLS-1$ - @Override - public void run() { - InputStreamReader is = new InputStreamReader(process.getInputStream()); - BufferedReader outReader = new BufferedReader(is); - - try { - while (true) { - String line = outReader.readLine(); - if (line != null) { - AdtPlugin.printToConsole("Emulator", line); - } else { - break; - } - } - } catch (IOException e) { - // do nothing. - } - } - }.start(); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java deleted file mode 100644 index a260350..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java +++ /dev/null @@ -1,705 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.launching; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.Client; -import com.android.ddmlib.Device; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; -import com.android.ddmlib.Device.DeviceState; -import com.android.ddmuilib.IImageLoader; -import com.android.ddmuilib.ImageHelper; -import com.android.ddmuilib.TableHelper; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.ddms.DdmsPlugin; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.avd.AvdManager; -import com.android.sdklib.avd.AvdManager.AvdInfo; -import com.android.sdkuilib.AvdSelector; - -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; - -import java.util.ArrayList; - -public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener { - - private final static int ICON_WIDTH = 16; - - private final static String PREFS_COL_SERIAL = "deviceChooser.serial"; //$NON-NLS-1$ - private final static String PREFS_COL_STATE = "deviceChooser.state"; //$NON-NLS-1$ - private final static String PREFS_COL_AVD = "deviceChooser.avd"; //$NON-NLS-1$ - private final static String PREFS_COL_TARGET = "deviceChooser.target"; //$NON-NLS-1$ - private final static String PREFS_COL_DEBUG = "deviceChooser.debug"; //$NON-NLS-1$ - - private Table mDeviceTable; - private TableViewer mViewer; - private AvdSelector mPreferredAvdSelector; - - private Image mDeviceImage; - private Image mEmulatorImage; - private Image mMatchImage; - private Image mNoMatchImage; - private Image mWarningImage; - - private final DeviceChooserResponse mResponse; - private final String mPackageName; - private final IAndroidTarget mProjectTarget; - private final Sdk mSdk; - - private final AvdInfo[] mFullAvdList; - - private Button mDeviceRadioButton; - - private boolean mDisableAvdSelectionChange = false; - - /** - * Basic Content Provider for a table full of {@link Device} objects. The input is - * a {@link AndroidDebugBridge}. - */ - private class ContentProvider implements IStructuredContentProvider { - public Object[] getElements(Object inputElement) { - if (inputElement instanceof AndroidDebugBridge) { - return ((AndroidDebugBridge)inputElement).getDevices(); - } - - return new Object[0]; - } - - public void dispose() { - // pass - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } - } - - - /** - * A Label Provider for the {@link TableViewer} in {@link DeviceChooserDialog}. - * It provides labels and images for {@link Device} objects. - */ - private class LabelProvider implements ITableLabelProvider { - - public Image getColumnImage(Object element, int columnIndex) { - if (element instanceof Device) { - Device device = (Device)element; - switch (columnIndex) { - case 0: - return device.isEmulator() ? mEmulatorImage : mDeviceImage; - - case 2: - // check for compatibility. - if (device.isEmulator() == false) { // physical device - // get the api level of the device - try { - String apiValue = device.getProperty( - IDevice.PROP_BUILD_VERSION_NUMBER); - if (apiValue != null) { - int api = Integer.parseInt(apiValue); - if (api >= mProjectTarget.getApiVersionNumber()) { - // if the project is compiling against an add-on, the optional - // API may be missing from the device. - return mProjectTarget.isPlatform() ? - mMatchImage : mWarningImage; - } else { - return mNoMatchImage; - } - } else { - return mWarningImage; - } - } catch (NumberFormatException e) { - // lets consider the device non compatible - return mNoMatchImage; - } - } else { - // get the AvdInfo - AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName()); - if (info == null) { - return mWarningImage; - } - return mProjectTarget.isCompatibleBaseFor(info.getTarget()) ? - mMatchImage : mNoMatchImage; - } - } - } - - return null; - } - - public String getColumnText(Object element, int columnIndex) { - if (element instanceof Device) { - Device device = (Device)element; - switch (columnIndex) { - case 0: - return device.getSerialNumber(); - case 1: - if (device.isEmulator()) { - return device.getAvdName(); - } else { - return "N/A"; // devices don't have AVD names. - } - case 2: - if (device.isEmulator()) { - AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName()); - if (info == null) { - return "?"; - } - return info.getTarget().getFullName(); - } else { - String deviceBuild = device.getProperty(IDevice.PROP_BUILD_VERSION); - if (deviceBuild == null) { - return "unknown"; - } - return deviceBuild; - } - case 3: - String debuggable = device.getProperty(IDevice.PROP_DEBUGGABLE); - if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$ - return "Yes"; - } else { - return ""; - } - case 4: - return getStateString(device); - } - } - - return null; - } - - public void addListener(ILabelProviderListener listener) { - // pass - } - - public void dispose() { - // pass - } - - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - public static class DeviceChooserResponse { - private AvdInfo mAvdToLaunch; - private Device mDeviceToUse; - - public void setDeviceToUse(Device d) { - mDeviceToUse = d; - mAvdToLaunch = null; - } - - public void setAvdToLaunch(AvdInfo avd) { - mAvdToLaunch = avd; - mDeviceToUse = null; - } - - public Device getDeviceToUse() { - return mDeviceToUse; - } - - public AvdInfo getAvdToLaunch() { - return mAvdToLaunch; - } - } - - public DeviceChooserDialog(Shell parent, DeviceChooserResponse response, String packageName, - IAndroidTarget projectTarget) { - super(parent); - mResponse = response; - mPackageName = packageName; - mProjectTarget = projectTarget; - mSdk = Sdk.getCurrent(); - - // get the full list of Android Virtual Devices - AvdManager avdManager = mSdk.getAvdManager(); - if (avdManager != null) { - mFullAvdList = avdManager.getAvds(); - } else { - mFullAvdList = null; - } - - loadImages(); - } - - private void cleanup() { - // done listening. - AndroidDebugBridge.removeDeviceChangeListener(this); - - mEmulatorImage.dispose(); - mDeviceImage.dispose(); - mMatchImage.dispose(); - mNoMatchImage.dispose(); - mWarningImage.dispose(); - } - - @Override - protected void okPressed() { - cleanup(); - super.okPressed(); - } - - @Override - protected void cancelPressed() { - cleanup(); - super.cancelPressed(); - } - - @Override - protected Control createContents(Composite parent) { - Control content = super.createContents(parent); - - // this must be called after createContents() has happened so that the - // ok button has been created (it's created after the call to createDialogArea) - updateDefaultSelection(); - - return content; - } - - - @Override - protected Control createDialogArea(Composite parent) { - Composite top = new Composite(parent, SWT.NONE); - top.setLayout(new GridLayout(1, true)); - - mDeviceRadioButton = new Button(top, SWT.RADIO); - mDeviceRadioButton.setText("Choose a running Android device"); - mDeviceRadioButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - boolean deviceMode = mDeviceRadioButton.getSelection(); - - mDeviceTable.setEnabled(deviceMode); - mPreferredAvdSelector.setEnabled(!deviceMode); - - if (deviceMode) { - handleDeviceSelection(); - } else { - mResponse.setAvdToLaunch(mPreferredAvdSelector.getFirstSelected()); - } - - enableOkButton(); - } - }); - mDeviceRadioButton.setSelection(true); - - - // offset the selector from the radio button - Composite offsetComp = new Composite(top, SWT.NONE); - offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - GridLayout layout = new GridLayout(1, false); - layout.marginRight = layout.marginHeight = 0; - layout.marginLeft = 30; - offsetComp.setLayout(layout); - - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION); - GridData gd; - mDeviceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH)); - gd.heightHint = 100; - - mDeviceTable.setHeaderVisible(true); - mDeviceTable.setLinesVisible(true); - - TableHelper.createTableColumn(mDeviceTable, "Serial Number", - SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$ - PREFS_COL_SERIAL, store); - - TableHelper.createTableColumn(mDeviceTable, "AVD Name", - SWT.LEFT, "engineering", //$NON-NLS-1$ - PREFS_COL_AVD, store); - - TableHelper.createTableColumn(mDeviceTable, "Target", - SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$ - PREFS_COL_TARGET, store); - - TableHelper.createTableColumn(mDeviceTable, "Debug", - SWT.LEFT, "Debug", //$NON-NLS-1$ - PREFS_COL_DEBUG, store); - - TableHelper.createTableColumn(mDeviceTable, "State", - SWT.LEFT, "bootloader", //$NON-NLS-1$ - PREFS_COL_STATE, store); - - // create the viewer for it - mViewer = new TableViewer(mDeviceTable); - mViewer.setContentProvider(new ContentProvider()); - mViewer.setLabelProvider(new LabelProvider()); - mViewer.setInput(AndroidDebugBridge.getBridge()); - mViewer.addDoubleClickListener(new IDoubleClickListener() { - public void doubleClick(DoubleClickEvent event) { - ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection) { - IStructuredSelection structuredSelection = (IStructuredSelection)selection; - Object object = structuredSelection.getFirstElement(); - if (object instanceof Device) { - mResponse.setDeviceToUse((Device)object); - } - } - } - }); - - Button radio2 = new Button(top, SWT.RADIO); - radio2.setText("Launch a new Android Virtual Device"); - - // offset the selector from the radio button - offsetComp = new Composite(top, SWT.NONE); - offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - layout = new GridLayout(1, false); - layout.marginRight = layout.marginHeight = 0; - layout.marginLeft = 30; - offsetComp.setLayout(layout); - - mPreferredAvdSelector = new AvdSelector(offsetComp, getNonRunningAvds(), mProjectTarget, - false /*allowMultipleSelection*/); - mPreferredAvdSelector.setTableHeightHint(100); - mPreferredAvdSelector.setEnabled(false); - mDeviceTable.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - handleDeviceSelection(); - } - }); - - mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - if (mDisableAvdSelectionChange == false) { - mResponse.setAvdToLaunch(mPreferredAvdSelector.getFirstSelected()); - enableOkButton(); - } - } - }); - - AndroidDebugBridge.addDeviceChangeListener(this); - - return top; - } - - private void loadImages() { - IImageLoader ddmsLoader = DdmsPlugin.getImageLoader(); - Display display = DdmsPlugin.getDisplay(); - IImageLoader adtLoader = AdtPlugin.getImageLoader(); - - if (mDeviceImage == null) { - mDeviceImage = ImageHelper.loadImage(ddmsLoader, display, - "device.png", //$NON-NLS-1$ - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_RED)); - } - if (mEmulatorImage == null) { - mEmulatorImage = ImageHelper.loadImage(ddmsLoader, display, - "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$ - display.getSystemColor(SWT.COLOR_BLUE)); - } - - if (mMatchImage == null) { - mMatchImage = ImageHelper.loadImage(adtLoader, display, - "match.png", //$NON-NLS-1$ - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_GREEN)); - } - - if (mNoMatchImage == null) { - mNoMatchImage = ImageHelper.loadImage(adtLoader, display, - "error.png", //$NON-NLS-1$ - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_RED)); - } - - if (mWarningImage == null) { - mWarningImage = ImageHelper.loadImage(adtLoader, display, - "warning.png", //$NON-NLS-1$ - ICON_WIDTH, ICON_WIDTH, - display.getSystemColor(SWT.COLOR_YELLOW)); - } - - } - - /** - * Returns a display string representing the state of the device. - * @param d the device - */ - private static String getStateString(Device d) { - DeviceState deviceState = d.getState(); - if (deviceState == DeviceState.ONLINE) { - return "Online"; - } else if (deviceState == DeviceState.OFFLINE) { - return "Offline"; - } else if (deviceState == DeviceState.BOOTLOADER) { - return "Bootloader"; - } - - return "??"; - } - - /** - * Sent when the a device is connected to the {@link AndroidDebugBridge}. - * <p/> - * This is sent from a non UI thread. - * @param device the new device. - * - * @see IDeviceChangeListener#deviceConnected(Device) - */ - public void deviceConnected(Device device) { - final DeviceChooserDialog dialog = this; - exec(new Runnable() { - public void run() { - if (mDeviceTable.isDisposed() == false) { - // refresh all - mViewer.refresh(); - - // update the selection - updateDefaultSelection(); - - // update the display of AvdInfo (since it's filtered to only display - // non running AVD.) - refillAvdList(); - } else { - // table is disposed, we need to do something. - // lets remove ourselves from the listener. - AndroidDebugBridge.removeDeviceChangeListener(dialog); - } - - } - }); - } - - /** - * Sent when the a device is connected to the {@link AndroidDebugBridge}. - * <p/> - * This is sent from a non UI thread. - * @param device the new device. - * - * @see IDeviceChangeListener#deviceDisconnected(Device) - */ - public void deviceDisconnected(Device device) { - deviceConnected(device); - } - - /** - * Sent when a device data changed, or when clients are started/terminated on the device. - * <p/> - * This is sent from a non UI thread. - * @param device the device that was updated. - * @param changeMask the mask indicating what changed. - * - * @see IDeviceChangeListener#deviceChanged(Device, int) - */ - public void deviceChanged(final Device device, int changeMask) { - if ((changeMask & (Device.CHANGE_STATE | Device.CHANGE_BUILD_INFO)) != 0) { - final DeviceChooserDialog dialog = this; - exec(new Runnable() { - public void run() { - if (mDeviceTable.isDisposed() == false) { - // refresh the device - mViewer.refresh(device); - - // update the defaultSelection. - updateDefaultSelection(); - - // update the display of AvdInfo (since it's filtered to only display - // non running AVD). This is done on deviceChanged because the avd name - // of a (emulator) device may be updated as the emulator boots. - refillAvdList(); - - // if the changed device is the current selection, - // we update the OK button based on its state. - if (device == mResponse.getDeviceToUse()) { - enableOkButton(); - } - - } else { - // table is disposed, we need to do something. - // lets remove ourselves from the listener. - AndroidDebugBridge.removeDeviceChangeListener(dialog); - } - } - }); - } - } - - /** - * Returns whether the dialog is in "device" mode (true), or in "avd" mode (false). - */ - private boolean isDeviceMode() { - return mDeviceRadioButton.getSelection(); - } - - /** - * Enables or disables the OK button of the dialog based on various selections in the dialog. - */ - private void enableOkButton() { - Button okButton = getButton(IDialogConstants.OK_ID); - - if (isDeviceMode()) { - okButton.setEnabled(mResponse.getDeviceToUse() != null && - mResponse.getDeviceToUse().isOnline()); - } else { - okButton.setEnabled(mResponse.getAvdToLaunch() != null); - } - } - - /** - * Executes the {@link Runnable} in the UI thread. - * @param runnable the runnable to execute. - */ - private void exec(Runnable runnable) { - try { - Display display = mDeviceTable.getDisplay(); - display.asyncExec(runnable); - } catch (SWTException e) { - // tree is disposed, we need to do something. lets remove ourselves from the listener. - AndroidDebugBridge.removeDeviceChangeListener(this); - } - } - - private void handleDeviceSelection() { - int count = mDeviceTable.getSelectionCount(); - if (count != 1) { - handleSelection(null); - } else { - int index = mDeviceTable.getSelectionIndex(); - Object data = mViewer.getElementAt(index); - if (data instanceof Device) { - handleSelection((Device)data); - } else { - handleSelection(null); - } - } - } - - private void handleSelection(Device device) { - mResponse.setDeviceToUse(device); - enableOkButton(); - } - - /** - * Look for a default device to select. This is done by looking for the running - * clients on each device and finding one similar to the one being launched. - * <p/> - * This is done every time the device list changed unless there is a already selection. - */ - private void updateDefaultSelection() { - if (mDeviceTable.getSelectionCount() == 0) { - AndroidDebugBridge bridge = AndroidDebugBridge.getBridge(); - - Device[] devices = bridge.getDevices(); - - for (Device device : devices) { - Client[] clients = device.getClients(); - - for (Client client : clients) { - - if (mPackageName.equals(client.getClientData().getClientDescription())) { - // found a match! Select it. - mViewer.setSelection(new StructuredSelection(device)); - handleSelection(device); - - // and we're done. - return; - } - } - } - } - - handleDeviceSelection(); - } - - /** - * Returns the list of {@link AvdInfo} that are not already running in an emulator. - */ - private AvdInfo[] getNonRunningAvds() { - ArrayList<AvdInfo> list = new ArrayList<AvdInfo>(); - - Device[] devices = AndroidDebugBridge.getBridge().getDevices(); - - // loop through all the Avd and put the one that are not running in the list. - avdLoop: for (AvdInfo info : mFullAvdList) { - for (Device d : devices) { - if (info.getName().equals(d.getAvdName())) { - continue avdLoop; - } - } - list.add(info); - } - - return list.toArray(new AvdInfo[list.size()]); - } - - /** - * Refills the AVD list keeping the current selection. - */ - private void refillAvdList() { - AvdInfo[] array = getNonRunningAvds(); - - // save the current selection - AvdInfo selected = mPreferredAvdSelector.getFirstSelected(); - - // disable selection change. - mDisableAvdSelectionChange = true; - - // set the new list in the selector - mPreferredAvdSelector.setAvds(array, mProjectTarget); - - // attempt to reselect the proper avd if needed - if (selected != null) { - if (mPreferredAvdSelector.setSelection(selected) == false) { - // looks like the selection is lost. this can happen if an emulator - // running the AVD that was selected was launched from outside of Eclipse). - mResponse.setAvdToLaunch(null); - enableOkButton(); - } - } - - // enable the selection change - mDisableAvdSelectionChange = false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java deleted file mode 100644 index bbd320b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.launching; - -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController.AndroidLaunchConfiguration; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestParser; -import com.android.ide.eclipse.common.project.BaseProjectHelper; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.debug.core.ILaunch; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.model.LaunchConfigurationDelegate; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; - -/** - * Implementation of an eclipse LauncConfigurationDelegate to launch android - * application in debug. - */ -public class LaunchConfigDelegate extends LaunchConfigurationDelegate { - final static int INVALID_DEBUG_PORT = -1; - - public final static String ANDROID_LAUNCH_TYPE_ID = - "com.android.ide.eclipse.adt.debug.LaunchConfigType"; //$NON-NLS-1$ - - /** Target mode parameters: true is automatic, false is manual */ - public static final String ATTR_TARGET_MODE = AdtPlugin.PLUGIN_ID + ".target"; //$NON-NLS-1$ - public static final boolean DEFAULT_TARGET_MODE = true; //automatic mode - - /** - * Launch action: - * <ul> - * <li>0: launch default activity</li> - * <li>1: launch specified activity. See {@link #ATTR_ACTIVITY}</li> - * <li>2: Do Nothing</li> - * </ul> - */ - public final static String ATTR_LAUNCH_ACTION = AdtPlugin.PLUGIN_ID + ".action"; //$NON-NLS-1$ - - /** Default launch action. This launches the activity that is setup to be found in the HOME - * screen. - */ - public final static int ACTION_DEFAULT = 0; - /** Launch action starting a specific activity. */ - public final static int ACTION_ACTIVITY = 1; - /** Launch action that does nothing. */ - public final static int ACTION_DO_NOTHING = 2; - /** Default launch action value. */ - public final static int DEFAULT_LAUNCH_ACTION = ACTION_DEFAULT; - - /** - * Activity to be launched if {@link #ATTR_LAUNCH_ACTION} is 1 - */ - public static final String ATTR_ACTIVITY = AdtPlugin.PLUGIN_ID + ".activity"; //$NON-NLS-1$ - - public static final String ATTR_AVD_NAME = AdtPlugin.PLUGIN_ID + ".avd"; //$NON-NLS-1$ - - public static final String ATTR_SPEED = AdtPlugin.PLUGIN_ID + ".speed"; //$NON-NLS-1$ - - /** - * Index of the default network speed setting for the emulator.<br> - * Get the emulator option with <code>EmulatorConfigTab.getSpeed(index)</code> - */ - public static final int DEFAULT_SPEED = 0; - - public static final String ATTR_DELAY = AdtPlugin.PLUGIN_ID + ".delay"; //$NON-NLS-1$ - - /** - * Index of the default network latency setting for the emulator.<br> - * Get the emulator option with <code>EmulatorConfigTab.getDelay(index)</code> - */ - public static final int DEFAULT_DELAY = 0; - - public static final String ATTR_COMMANDLINE = AdtPlugin.PLUGIN_ID + ".commandline"; //$NON-NLS-1$ - - public static final String ATTR_WIPE_DATA = AdtPlugin.PLUGIN_ID + ".wipedata"; //$NON-NLS-1$ - public static final boolean DEFAULT_WIPE_DATA = false; - - public static final String ATTR_NO_BOOT_ANIM = AdtPlugin.PLUGIN_ID + ".nobootanim"; //$NON-NLS-1$ - public static final boolean DEFAULT_NO_BOOT_ANIM = false; - - public static final String ATTR_DEBUG_PORT = - AdtPlugin.PLUGIN_ID + ".debugPort"; //$NON-NLS-1$ - - public void launch(ILaunchConfiguration configuration, String mode, - ILaunch launch, IProgressMonitor monitor) throws CoreException { - // We need to check if it's a standard launch or if it's a launch - // to debug an application already running. - int debugPort = AndroidLaunchController.getPortForConfig(configuration); - - // get the project - IProject project = getProject(configuration); - - // first we make sure the launch is of the proper type - AndroidLaunch androidLaunch = null; - if (launch instanceof AndroidLaunch) { - androidLaunch = (AndroidLaunch)launch; - } else { - // wrong type, not sure how we got there, but we don't do - // anything else - AdtPlugin.printErrorToConsole(project, "Wrong Launch Type!"); - return; - } - - // if we have a valid debug port, this means we're debugging an app - // that's already launched. - if (debugPort != INVALID_DEBUG_PORT) { - AndroidLaunchController.launchRemoteDebugger(debugPort, androidLaunch, monitor); - return; - } - - if (project == null) { - AdtPlugin.printErrorToConsole("Couldn't get project object!"); - androidLaunch.stopLaunch(); - return; - } - - // check if the project has errors, and abort in this case. - if (ProjectHelper.hasError(project, true)) { - AdtPlugin.displayError("Android Launch", - "Your project contains error(s), please fix them before running your application."); - return; - } - - AdtPlugin.printToConsole(project, "------------------------------"); //$NON-NLS-1$ - AdtPlugin.printToConsole(project, "Android Launch!"); - - // check if the project is using the proper sdk. - // if that throws an exception, we simply let it propage to the caller. - if (checkAndroidProject(project) == false) { - AdtPlugin.printErrorToConsole(project, "Project is not an Android Project. Aborting!"); - androidLaunch.stopLaunch(); - return; - } - - // Check adb status and abort if needed. - AndroidDebugBridge bridge = AndroidDebugBridge.getBridge(); - if (bridge == null || bridge.isConnected() == false) { - try { - int connections = -1; - int restarts = -1; - if (bridge != null) { - connections = bridge.getConnectionAttemptCount(); - restarts = bridge.getRestartAttemptCount(); - } - - // if we get -1, the device monitor is not even setup (anymore?). - // We need to ask the user to restart eclipse. - // This shouldn't happen, but it's better to let the user know in case it does. - if (connections == -1 || restarts == -1) { - AdtPlugin.printErrorToConsole(project, - "The connection to adb is down, and a severe error has occured.", - "You must restart adb and Eclipse.", - String.format( - "Please ensure that adb is correctly located at '%1$s' and can be executed.", - AdtPlugin.getOsAbsoluteAdb())); - return; - } - - if (restarts == 0) { - AdtPlugin.printErrorToConsole(project, - "Connection with adb was interrupted.", - String.format("%1$s attempts have been made to reconnect.", connections), - "You may want to manually restart adb from the Devices view."); - } else { - AdtPlugin.printErrorToConsole(project, - "Connection with adb was interrupted, and attempts to reconnect have failed.", - String.format("%1$s attempts have been made to restart adb.", restarts), - "You may want to manually restart adb from the Devices view."); - - } - return; - } finally { - androidLaunch.stopLaunch(); - } - } - - // since adb is working, we let the user know - // TODO have a verbose mode for launch with more info (or some of the less useful info we now have). - AdtPlugin.printToConsole(project, "adb is running normally."); - - // make a config class - AndroidLaunchConfiguration config = new AndroidLaunchConfiguration(); - - // fill it with the config coming from the ILaunchConfiguration object - config.set(configuration); - - // get the launch controller singleton - AndroidLaunchController controller = AndroidLaunchController.getInstance(); - - // get the application package - IFile applicationPackage = getApplicationPackage(project); - if (applicationPackage == null) { - androidLaunch.stopLaunch(); - return; - } - - // we need some information from the manifest - AndroidManifestParser manifestParser = AndroidManifestParser.parse( - BaseProjectHelper.getJavaProject(project), null /* errorListener */, - true /* gatherData */, false /* markErrors */); - - if (manifestParser == null) { - AdtPlugin.printErrorToConsole(project, "Failed to parse AndroidManifest: aborting!"); - androidLaunch.stopLaunch(); - return; - } - - String activityName = null; - - if (config.mLaunchAction == ACTION_ACTIVITY) { - // Get the activity name defined in the config - activityName = getActivityName(configuration); - - // Get the full activity list and make sure the one we got matches. - String[] activities = manifestParser.getActivities(); - - // first we check that there are, in fact, activities. - if (activities.length == 0) { - // if the activities list is null, then the manifest is empty - // and we can't launch the app. We'll revert to a sync-only launch - AdtPlugin.printErrorToConsole(project, - "The Manifest defines no activity!", - "The launch will only sync the application package on the device!"); - config.mLaunchAction = ACTION_DO_NOTHING; - } else if (activityName == null) { - // if the activity we got is null, we look for the default one. - AdtPlugin.printErrorToConsole(project, - "No activity specified! Getting the launcher activity."); - activityName = manifestParser.getLauncherActivity(); - - // if there's no default activity. We revert to a sync-only launch. - if (activityName == null) { - revertToNoActionLaunch(project, config); - } - } else { - - // check the one we got from the config matches any from the list - boolean match = false; - for (String a : activities) { - if (a != null && a.equals(activityName)) { - match = true; - break; - } - } - - // if we didn't find a match, we revert to the default activity if any. - if (match == false) { - AdtPlugin.printErrorToConsole(project, - "The specified activity does not exist! Getting the launcher activity."); - activityName = manifestParser.getLauncherActivity(); - - // if there's no default activity. We revert to a sync-only launch. - if (activityName == null) { - revertToNoActionLaunch(project, config); - } - } - } - } else if (config.mLaunchAction == ACTION_DEFAULT) { - activityName = manifestParser.getLauncherActivity(); - - // if there's no default activity. We revert to a sync-only launch. - if (activityName == null) { - revertToNoActionLaunch(project, config); - } - } - - // everything seems fine, we ask the launch controller to handle - // the rest - controller.launch(project, mode, applicationPackage, manifestParser.getPackage(), - manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), - activityName, config, androidLaunch, monitor); - } - - @Override - public boolean buildForLaunch(ILaunchConfiguration configuration, - String mode, IProgressMonitor monitor) throws CoreException { - - // need to check we have everything - IProject project = getProject(configuration); - - if (project != null) { - // force an incremental build to be sure the resources will - // be updated if they were not saved before the launch was launched. - return true; - } - - throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - 1 /* code, unused */, "Can't find the project!", null /* exception */)); - } - - /** - * {@inheritDoc} - * @throws CoreException - */ - @Override - public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) - throws CoreException { - return new AndroidLaunch(configuration, mode, null); - } - - /** - * Returns the IProject object matching the name found in the configuration - * object under the name - * <code>IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME</code> - * @param configuration - * @return The IProject object or null - */ - private IProject getProject(ILaunchConfiguration configuration){ - // get the project name from the config - String projectName; - try { - projectName = configuration.getAttribute( - IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); - } catch (CoreException e) { - return null; - } - - // get the current workspace - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - - // and return the project with the name from the config - return workspace.getRoot().getProject(projectName); - } - - /** - * Checks the project is an android project. - * @param project The project to check - * @return true if the project is an android SDK. - * @throws CoreException - */ - private boolean checkAndroidProject(IProject project) throws CoreException { - // check if the project is a java and an android project. - if (project.hasNature(JavaCore.NATURE_ID) == false) { - String msg = String.format("%1$s is not a Java project!", project.getName()); - AdtPlugin.displayError("Android Launch", msg); - return false; - } - - if (project.hasNature(AndroidConstants.NATURE) == false) { - String msg = String.format("%1$s is not an Android project!", project.getName()); - AdtPlugin.displayError("Android Launch", msg); - return false; - } - - return true; - } - - - /** - * Returns the android package file as an IFile object for the specified - * project. - * @param project The project - * @return The android package as an IFile object or null if not found. - */ - private IFile getApplicationPackage(IProject project) { - // get the output folder - IFolder outputLocation = BaseProjectHelper.getOutputFolder(project); - - if (outputLocation == null) { - AdtPlugin.printErrorToConsole(project, - "Failed to get the output location of the project. Check build path properties" - ); - return null; - } - - - // get the package path - String packageName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE; - IResource r = outputLocation.findMember(packageName); - - // check the package is present - if (r instanceof IFile && r.exists()) { - return (IFile)r; - } - - String msg = String.format("Could not find %1$s!", packageName); - AdtPlugin.printErrorToConsole(project, msg); - - return null; - } - - /** - * Returns the name of the activity. - */ - private String getActivityName(ILaunchConfiguration configuration) { - String empty = ""; - String activityName; - try { - activityName = configuration.getAttribute(ATTR_ACTIVITY, empty); - } catch (CoreException e) { - return null; - } - - return (activityName != empty) ? activityName : null; - } - - private final void revertToNoActionLaunch(IProject project, AndroidLaunchConfiguration config) { - AdtPlugin.printErrorToConsole(project, - "No Launcher activity found!", - "The launch will only sync the application package on the device!"); - config.mLaunchAction = ACTION_DO_NOTHING; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchShortcut.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchShortcut.java deleted file mode 100644 index 92677f1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchShortcut.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.launching; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.ui.DebugUITools; -import org.eclipse.debug.ui.ILaunchShortcut; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IEditorPart; - -/** - * Launch shortcut to launch debug/run configuration directly. - */ -public class LaunchShortcut implements ILaunchShortcut { - - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchShortcut#launch( - * org.eclipse.jface.viewers.ISelection, java.lang.String) - */ - public void launch(ISelection selection, String mode) { - if (selection instanceof IStructuredSelection) { - - // get the object and the project from it - IStructuredSelection structSelect = (IStructuredSelection)selection; - Object o = structSelect.getFirstElement(); - - // get the first (and normally only) element - if (o instanceof IAdaptable) { - IResource r = (IResource)((IAdaptable)o).getAdapter(IResource.class); - - // get the project from the resource - if (r != null) { - IProject project = r.getProject(); - - if (project != null) { - // and launch - launch(project, mode); - } - } - } - } - } - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchShortcut#launch( - * org.eclipse.ui.IEditorPart, java.lang.String) - */ - public void launch(IEditorPart editor, String mode) { - // since we force the shortcut to only work on selection in the - // package explorer, this will never be called. - } - - - /** - * Launch a config for the specified project. - * @param project The project to launch - * @param mode The launch mode ("debug", "run" or "profile") - */ - private void launch(IProject project, String mode) { - // get an existing or new launch configuration - ILaunchConfiguration config = AndroidLaunchController.getLaunchConfig(project); - - if (config != null) { - // and launch! - DebugUITools.launch(config, mode); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java deleted file mode 100644 index d919c1f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.ui; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.debug.launching.LaunchConfigDelegate; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.ddms.DdmsPlugin; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.avd.AvdManager; -import com.android.sdklib.avd.AvdManager.AvdInfo; -import com.android.sdkuilib.AvdSelector; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; -import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** - * Launch configuration tab to control the parameters of the Emulator - */ -public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { - - private final static String[][] NETWORK_SPEEDS = new String[][] { - { "Full", "full" }, //$NON-NLS-2$ - { "GSM", "gsm" }, //$NON-NLS-2$ - { "HSCSD", "hscsd" }, //$NON-NLS-2$ - { "GPRS", "gprs" }, //$NON-NLS-2$ - { "EDGE", "edge" }, //$NON-NLS-2$ - { "UMTS", "umts" }, //$NON-NLS-2$ - { "HSPDA", "hsdpa" }, //$NON-NLS-2$ - }; - - private final static String[][] NETWORK_LATENCIES = new String[][] { - { "None", "none" }, //$NON-NLS-2$ - { "GPRS", "gprs" }, //$NON-NLS-2$ - { "EDGE", "edge" }, //$NON-NLS-2$ - { "UMTS", "umts" }, //$NON-NLS-2$ - }; - - private Button mAutoTargetButton; - private Button mManualTargetButton; - - private AvdSelector mPreferredAvdSelector; - - private Combo mSpeedCombo; - - private Combo mDelayCombo; - - private Group mEmulatorOptionsGroup; - - private Text mEmulatorCLOptions; - - private Button mWipeDataButton; - - private Button mNoBootAnimButton; - - private Label mPreferredAvdLabel; - - /** - * Returns the emulator ready speed option value. - * @param value The index of the combo selection. - */ - public static String getSpeed(int value) { - try { - return NETWORK_SPEEDS[value][1]; - } catch (ArrayIndexOutOfBoundsException e) { - return NETWORK_SPEEDS[LaunchConfigDelegate.DEFAULT_SPEED][1]; - } - } - - /** - * Returns the emulator ready network latency value. - * @param value The index of the combo selection. - */ - public static String getDelay(int value) { - try { - return NETWORK_LATENCIES[value][1]; - } catch (ArrayIndexOutOfBoundsException e) { - return NETWORK_LATENCIES[LaunchConfigDelegate.DEFAULT_DELAY][1]; - } - } - - /** - * - */ - public EmulatorConfigTab() { - } - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite) - */ - public void createControl(Composite parent) { - Font font = parent.getFont(); - - Composite topComp = new Composite(parent, SWT.NONE); - setControl(topComp); - GridLayout topLayout = new GridLayout(); - topLayout.numColumns = 1; - topLayout.verticalSpacing = 0; - topComp.setLayout(topLayout); - topComp.setFont(font); - - GridData gd; - GridLayout layout; - - // radio button for the target mode - Group targetModeGroup = new Group(topComp, SWT.NONE); - targetModeGroup.setText("Device Target Selection Mode"); - gd = new GridData(GridData.FILL_HORIZONTAL); - targetModeGroup.setLayoutData(gd); - layout = new GridLayout(); - layout.numColumns = 1; - targetModeGroup.setLayout(layout); - targetModeGroup.setFont(font); - - mManualTargetButton = new Button(targetModeGroup, SWT.RADIO); - mManualTargetButton.setText("Manual"); - // Since there are only 2 radio buttons, we can put a listener on only one (they - // are both called on select and unselect event. - - // add the radio button - mAutoTargetButton = new Button(targetModeGroup, SWT.RADIO); - mAutoTargetButton.setText("Automatic"); - mAutoTargetButton.setSelection(true); - mAutoTargetButton.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - - boolean auto = mAutoTargetButton.getSelection(); - mPreferredAvdSelector.setEnabled(auto); - mPreferredAvdLabel.setEnabled(auto); - } - }); - - Composite offsetComp = new Composite(targetModeGroup, SWT.NONE); - offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - layout = new GridLayout(1, false); - layout.marginRight = layout.marginHeight = 0; - layout.marginLeft = 30; - offsetComp.setLayout(layout); - - mPreferredAvdLabel = new Label(offsetComp, SWT.NONE); - mPreferredAvdLabel.setText("Select a preferred Android Virtual Device:"); - AvdInfo[] avds = new AvdInfo[0]; - mPreferredAvdSelector = new AvdSelector(offsetComp, avds, - false /*allowMultipleSelection*/); - mPreferredAvdSelector.setTableHeightHint(100); - mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - } - }); - - // emulator size - mEmulatorOptionsGroup = new Group(topComp, SWT.NONE); - mEmulatorOptionsGroup.setText("Emulator launch parameters:"); - mEmulatorOptionsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - layout = new GridLayout(); - layout.numColumns = 2; - mEmulatorOptionsGroup.setLayout(layout); - mEmulatorOptionsGroup.setFont(font); - - // network options - new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Speed:"); - - mSpeedCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY); - for (String[] speed : NETWORK_SPEEDS) { - mSpeedCombo.add(speed[0]); - } - mSpeedCombo.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - } - }); - mSpeedCombo.pack(); - - new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Latency:"); - - mDelayCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY); - - for (String[] delay : NETWORK_LATENCIES) { - mDelayCombo.add(delay[0]); - } - mDelayCombo.addSelectionListener(new SelectionAdapter() { - // called when selection changes - @Override - public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - } - }); - mDelayCombo.pack(); - - // wipe data option - mWipeDataButton = new Button(mEmulatorOptionsGroup, SWT.CHECK); - mWipeDataButton.setText("Wipe User Data"); - mWipeDataButton.setToolTipText("Check this if you want to wipe your user data each time you start the emulator. You will be prompted for confirmation when the emulator starts."); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - mWipeDataButton.setLayoutData(gd); - mWipeDataButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - } - }); - - // no boot anim option - mNoBootAnimButton = new Button(mEmulatorOptionsGroup, SWT.CHECK); - mNoBootAnimButton.setText("Disable Boot Animation"); - mNoBootAnimButton.setToolTipText("Check this if you want to disable the boot animation. This can help the emulator start faster on slow machines."); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - mNoBootAnimButton.setLayoutData(gd); - mNoBootAnimButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - updateLaunchConfigurationDialog(); - } - }); - - // custom command line option for emulator - Label l = new Label(mEmulatorOptionsGroup, SWT.NONE); - l.setText("Additional Emulator Command Line Options"); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - l.setLayoutData(gd); - - mEmulatorCLOptions = new Text(mEmulatorOptionsGroup, SWT.BORDER); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - mEmulatorCLOptions.setLayoutData(gd); - mEmulatorCLOptions.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - updateLaunchConfigurationDialog(); - } - }); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName() - */ - public String getName() { - return "Target"; - } - - @Override - public Image getImage() { - return DdmsPlugin.getImageLoader().loadImage("emulator.png", null); //$NON-NLS-1$ - } - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) - */ - public void initializeFrom(ILaunchConfiguration configuration) { - AvdManager avdManager = Sdk.getCurrent().getAvdManager(); - - boolean value = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic - try { - value = configuration.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, value); - } catch (CoreException e) { - // let's not do anything here, we'll use the default value - } - mAutoTargetButton.setSelection(value); - mManualTargetButton.setSelection(!value); - - // look for the project name to get its target. - String stringValue = ""; - try { - stringValue = configuration.getAttribute( - IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, stringValue); - } catch (CoreException ce) { - // let's not do anything here, we'll use the default value - } - - IProject project = null; - - // get the list of existing Android projects from the workspace. - IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(); - if (projects != null) { - // look for the project whose name we read from the configuration. - for (IJavaProject p : projects) { - if (p.getElementName().equals(stringValue)) { - project = p.getProject(); - break; - } - } - } - - // update the AVD list - AvdInfo[] avds = null; - if (avdManager != null) { - avds = avdManager.getAvds(); - } - - IAndroidTarget projectTarget = null; - if (project != null) { - projectTarget = Sdk.getCurrent().getTarget(project); - } else { - avds = null; // no project? we don't want to display any "compatible" AVDs. - } - - mPreferredAvdSelector.setAvds(avds, projectTarget); - - stringValue = ""; - try { - stringValue = configuration.getAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, - stringValue); - } catch (CoreException e) { - // let's not do anything here, we'll use the default value - } - - if (stringValue != null && stringValue.length() > 0 && avdManager != null) { - AvdInfo targetAvd = avdManager.getAvd(stringValue); - mPreferredAvdSelector.setSelection(targetAvd); - } else { - mPreferredAvdSelector.setSelection(null); - } - - value = LaunchConfigDelegate.DEFAULT_WIPE_DATA; - try { - value = configuration.getAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, value); - } catch (CoreException e) { - // let's not do anything here, we'll use the default value - } - mWipeDataButton.setSelection(value); - - value = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM; - try { - value = configuration.getAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, value); - } catch (CoreException e) { - // let's not do anything here, we'll use the default value - } - mNoBootAnimButton.setSelection(value); - - int index = -1; - - index = LaunchConfigDelegate.DEFAULT_SPEED; - try { - index = configuration.getAttribute(LaunchConfigDelegate.ATTR_SPEED, - index); - } catch (CoreException e) { - // let's not do anything here, we'll use the default value - } - if (index == -1) { - mSpeedCombo.clearSelection(); - } else { - mSpeedCombo.select(index); - } - - index = LaunchConfigDelegate.DEFAULT_DELAY; - try { - index = configuration.getAttribute(LaunchConfigDelegate.ATTR_DELAY, - index); - } catch (CoreException e) { - // let's not do anything here, we'll put a proper value in - // performApply anyway - } - if (index == -1) { - mDelayCombo.clearSelection(); - } else { - mDelayCombo.select(index); - } - - String commandLine = null; - try { - commandLine = configuration.getAttribute( - LaunchConfigDelegate.ATTR_COMMANDLINE, ""); //$NON-NLS-1$ - } catch (CoreException e) { - // let's not do anything here, we'll use the default value - } - if (commandLine != null) { - mEmulatorCLOptions.setText(commandLine); - } - } - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) - */ - public void performApply(ILaunchConfigurationWorkingCopy configuration) { - configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, - mAutoTargetButton.getSelection()); - AvdInfo avd = mPreferredAvdSelector.getFirstSelected(); - if (avd != null) { - configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, avd.getName()); - } else { - configuration.setAttribute(LaunchConfigDelegate.ATTR_AVD_NAME, (String)null); - } - configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED, - mSpeedCombo.getSelectionIndex()); - configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY, - mDelayCombo.getSelectionIndex()); - configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, - mEmulatorCLOptions.getText()); - configuration.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, - mWipeDataButton.getSelection()); - configuration.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, - mNoBootAnimButton.getSelection()); - } - - /* (non-Javadoc) - * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy) - */ - public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { - configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, - LaunchConfigDelegate.DEFAULT_TARGET_MODE); - configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED, - LaunchConfigDelegate.DEFAULT_SPEED); - configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY, - LaunchConfigDelegate.DEFAULT_DELAY); - configuration.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA, - LaunchConfigDelegate.DEFAULT_WIPE_DATA); - configuration.setAttribute(LaunchConfigDelegate.ATTR_NO_BOOT_ANIM, - LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM); - - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - String emuOptions = store.getString(AdtPlugin.PREFS_EMU_OPTIONS); - configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, emuOptions); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/LaunchConfigTabGroup.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/LaunchConfigTabGroup.java deleted file mode 100644 index c0dbd54..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/LaunchConfigTabGroup.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.ui; - -import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; -import org.eclipse.debug.ui.CommonTab; -import org.eclipse.debug.ui.ILaunchConfigurationDialog; -import org.eclipse.debug.ui.ILaunchConfigurationTab; - -/** - * Tab group object for Android Launch Config type. - */ -public class LaunchConfigTabGroup extends AbstractLaunchConfigurationTabGroup { - - public LaunchConfigTabGroup() { - } - - public void createTabs(ILaunchConfigurationDialog dialog, String mode) { - ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] { - new MainLaunchConfigTab(), - new EmulatorConfigTab(), - new CommonTab() - }; - setTabs(tabs); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java deleted file mode 100644 index 6a40ed0..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (C) 2007 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.debug.ui; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController; -import com.android.ide.eclipse.adt.debug.launching.LaunchConfigDelegate; -import com.android.ide.eclipse.common.project.AndroidManifestParser; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.common.project.ProjectChooserHelper; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; -import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; -import org.eclipse.debug.ui.ILaunchConfigurationTab; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Text; - -/** - * Class for the main launch configuration tab. - */ -public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab { - - protected static final String EMPTY_STRING = ""; //$NON-NLS-1$ - - protected Text mProjText; - private Button mProjButton; - - private Combo mActivityCombo; - private String[] mActivities; - - private WidgetListener mListener = new WidgetListener(); - - private Button mDefaultActionButton; - private Button mActivityActionButton; - private Button mDoNothingActionButton; - private int mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION; - - private ProjectChooserHelper mProjectChooserHelper; - - /** - * A listener which handles widget change events for the controls in this - * tab. - */ - private class WidgetListener implements ModifyListener, SelectionListener { - - public void modifyText(ModifyEvent e) { - IProject project = checkParameters(); - loadActivities(project); - setDirty(true); - } - - public void widgetDefaultSelected(SelectionEvent e) {/* do nothing */ - } - - public void widgetSelected(SelectionEvent e) { - Object source = e.getSource(); - if (source == mProjButton) { - handleProjectButtonSelected(); - } else { - checkParameters(); - } - } - } - - public MainLaunchConfigTab() { - } - - public void createControl(Composite parent) { - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); - - Font font = parent.getFont(); - Composite comp = new Composite(parent, SWT.NONE); - setControl(comp); - GridLayout topLayout = new GridLayout(); - topLayout.verticalSpacing = 0; - comp.setLayout(topLayout); - comp.setFont(font); - createProjectEditor(comp); - createVerticalSpacer(comp, 1); - - // create the combo for the activity chooser - Group group = new Group(comp, SWT.NONE); - group.setText("Launch Action:"); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - group.setLayoutData(gd); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - group.setLayout(layout); - group.setFont(font); - - mDefaultActionButton = new Button(group, SWT.RADIO); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - mDefaultActionButton.setLayoutData(gd); - mDefaultActionButton.setText("Launch Default Activity"); - mDefaultActionButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // event are received for both selection and deselection, so we only process - // the selection event to avoid doing it twice. - if (mDefaultActionButton.getSelection() == true) { - mLaunchAction = LaunchConfigDelegate.ACTION_DEFAULT; - mActivityCombo.setEnabled(false); - checkParameters(); - } - } - }); - - mActivityActionButton = new Button(group, SWT.RADIO); - mActivityActionButton.setText("Launch:"); - mActivityActionButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // event are received for both selection and deselection, so we only process - // the selection event to avoid doing it twice. - if (mActivityActionButton.getSelection() == true) { - mLaunchAction = LaunchConfigDelegate.ACTION_ACTIVITY; - mActivityCombo.setEnabled(true); - checkParameters(); - } - } - }); - - mActivityCombo = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY); - gd = new GridData(GridData.FILL_HORIZONTAL); - mActivityCombo.setLayoutData(gd); - mActivityCombo.clearSelection(); - mActivityCombo.setEnabled(false); - mActivityCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - checkParameters(); - } - }); - - mDoNothingActionButton = new Button(group, SWT.RADIO); - gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - mDoNothingActionButton.setLayoutData(gd); - mDoNothingActionButton.setText("Do Nothing"); - mDoNothingActionButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // event are received for both selection and deselection, so we only process - // the selection event to avoid doing it twice. - if (mDoNothingActionButton.getSelection() == true) { - mLaunchAction = LaunchConfigDelegate.ACTION_DO_NOTHING; - mActivityCombo.setEnabled(false); - checkParameters(); - } - } - }); - - } - - public String getName() { - return "Android"; - } - - @Override - public Image getImage() { - return AdtPlugin.getImageLoader().loadImage("mainLaunchTab.png", null); - } - - - public void performApply(ILaunchConfigurationWorkingCopy configuration) { - configuration.setAttribute( - IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, mProjText.getText()); - configuration.setAttribute( - IJavaLaunchConfigurationConstants.ATTR_ALLOW_TERMINATE, true); - - // add the launch mode - configuration.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, mLaunchAction); - - // add the activity - int selection = mActivityCombo.getSelectionIndex(); - if (mActivities != null && selection >=0 && selection < mActivities.length) { - configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, mActivities[selection]); - } - - // link the project and the launch config. - mapResources(configuration); - } - - public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { - configuration.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, - LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION); - } - - /** - * Creates the widgets for specifying a main type. - * - * @param parent the parent composite - */ - protected void createProjectEditor(Composite parent) { - Font font = parent.getFont(); - Group group = new Group(parent, SWT.NONE); - group.setText("Project:"); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - group.setLayoutData(gd); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - group.setLayout(layout); - group.setFont(font); - mProjText = new Text(group, SWT.SINGLE | SWT.BORDER); - gd = new GridData(GridData.FILL_HORIZONTAL); - mProjText.setLayoutData(gd); - mProjText.setFont(font); - mProjText.addModifyListener(mListener); - mProjButton = createPushButton(group, "Browse...", null); - mProjButton.addSelectionListener(mListener); - } - - /** - * returns the default listener from this class. For all subclasses this - * listener will only provide the functi Jaonality of updating the current - * tab - * - * @return a widget listener - */ - protected WidgetListener getDefaultListener() { - return mListener; - } - - /** - * Return the {@link IJavaProject} corresponding to the project name in the project - * name text field, or null if the text does not match a project name. - * @param javaModel the Java Model object corresponding for the current workspace root. - * @return a IJavaProject object or null. - */ - protected IJavaProject getJavaProject(IJavaModel javaModel) { - String projectName = mProjText.getText().trim(); - if (projectName.length() < 1) { - return null; - } - return javaModel.getJavaProject(projectName); - } - - /** - * Show a dialog that lets the user select a project. This in turn provides - * context for the main type, allowing the user to key a main type name, or - * constraining the search for main types to the specified project. - */ - protected void handleProjectButtonSelected() { - IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject( - mProjText.getText().trim()); - if (javaProject == null) { - return; - }// end if - String projectName = javaProject.getElementName(); - mProjText.setText(projectName); - - // get the list of activities and fill the combo - IProject project = javaProject.getProject(); - loadActivities(project); - }// end handle selected - - /** - * Initializes this tab's controls with values from the given - * launch configuration. This method is called when - * a configuration is selected to view or edit, after this - * tab's control has been created. - * - * @param config launch configuration - * - * @see ILaunchConfigurationTab - */ - public void initializeFrom(ILaunchConfiguration config) { - String projectName = EMPTY_STRING; - try { - projectName = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, - EMPTY_STRING); - }// end try - catch (CoreException ce) { - } - mProjText.setText(projectName); - - // get the list of projects - IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null); - - if (projects != null) { - // look for the currently selected project - IProject proj = null; - for (IJavaProject p : projects) { - if (p.getElementName().equals(projectName)) { - proj = p.getProject(); - break; - } - } - - loadActivities(proj); - } - - // load the launch action. - mLaunchAction = LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION; - try { - mLaunchAction = config.getAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION, - mLaunchAction); - } catch (CoreException e) { - // nothing to be done really. launchAction will keep its default value. - } - - mDefaultActionButton.setSelection(mLaunchAction == LaunchConfigDelegate.ACTION_DEFAULT); - mActivityActionButton.setSelection(mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY); - mDoNothingActionButton.setSelection( - mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING); - - // now look for the activity and load it if present, otherwise, revert - // to the current one. - String activityName = EMPTY_STRING; - try { - activityName = config.getAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, EMPTY_STRING); - }// end try - catch (CoreException ce) { - // nothing to be done really. activityName will stay empty - } - - if (mLaunchAction != LaunchConfigDelegate.ACTION_ACTIVITY) { - mActivityCombo.setEnabled(false); - mActivityCombo.clearSelection(); - } else { - mActivityCombo.setEnabled(true); - if (activityName == null || activityName.equals(EMPTY_STRING)) { - mActivityCombo.clearSelection(); - } else if (mActivities != null && mActivities.length > 0) { - // look for the name of the activity in the combo. - boolean found = false; - for (int i = 0 ; i < mActivities.length ; i++) { - if (activityName.equals(mActivities[i])) { - found = true; - mActivityCombo.select(i); - break; - } - } - - // if we haven't found a matching activity we clear the combo selection - if (found == false) { - mActivityCombo.clearSelection(); - } - } - } - } - - /** - * Associates the launch config and the project. This allows Eclipse to delete the launch - * config when the project is deleted. - * - * @param config the launch config working copy. - */ - protected void mapResources(ILaunchConfigurationWorkingCopy config) { - // get the java model - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - - // get the IJavaProject described by the text field. - IJavaProject javaProject = getJavaProject(javaModel); - IResource[] resources = null; - if (javaProject != null) { - resources = AndroidLaunchController.getResourcesToMap(javaProject.getProject()); - } - config.setMappedResources(resources); - } - - /** - * Loads the ui with the activities of the specified project, and stores the - * activities in <code>mActivities</code>. - * <p/> - * First activity is selected by default if present. - * - * @param project The project to load the activities from. - */ - private void loadActivities(IProject project) { - if (project != null) { - try { - // parse the manifest for the list of activities. - AndroidManifestParser manifestParser = AndroidManifestParser.parse( - BaseProjectHelper.getJavaProject(project), null /* errorListener */, - true /* gatherData */, false /* markErrors */); - if (manifestParser != null) { - mActivities = manifestParser.getActivities(); - - mActivityCombo.removeAll(); - - if (mActivities.length > 0) { - if (mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY) { - mActivityCombo.setEnabled(true); - } - for (String s : mActivities) { - mActivityCombo.add(s); - } - } else { - mActivityCombo.setEnabled(false); - } - - // the selection will be set when we update the ui from the current - // config object. - mActivityCombo.clearSelection(); - - return; - } - - } catch (CoreException e) { - // The AndroidManifest parsing failed. The builders must have reported the errors - // already so there's nothing to do. - } - } - - // if we reach this point, either project is null, or we got an exception during - // the parsing. In either case, we empty the activity list. - mActivityCombo.removeAll(); - mActivities = null; - } - - /** - * Checks the parameters for correctness, and update the error message and buttons. - * @return the current IProject of this launch config. - */ - private IProject checkParameters() { - try { - //test the project name first! - String text = mProjText.getText(); - if (text.length() == 0) { - setErrorMessage("Project Name is required!"); - } else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) { - setErrorMessage("Project name contains unsupported characters!"); - } else { - IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null); - IProject found = null; - for (IJavaProject javaProject : projects) { - if (javaProject.getProject().getName().equals(text)) { - found = javaProject.getProject(); - break; - } - - } - - if (found != null) { - setErrorMessage(null); - } else { - setErrorMessage(String.format("There is no android project named '%1$s'", - text)); - } - - return found; - } - } finally { - updateLaunchConfigurationDialog(); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/messages.properties deleted file mode 100644 index dfb0eb2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/messages.properties +++ /dev/null @@ -1,16 +0,0 @@ -Dialog_Title_SDK_Location=Android SDK Location -SDK_Not_Setup=The location of the Android SDK has not been setup. Please go to Preferences > Android and set it up -Error_Check_Prefs=%1$s\nPlease check the Android plugin's preferences. -Could_Not_Find_Folder=Could not find SDK folder '%1$s'. -Could_Not_Find_Folder_In_SDK=Could not find folder '%1$s' inside SDK '%2$s'. -Could_Not_Find=Could not find %1$s\! -VersionCheck_SDK_Milestone_Too_Low=This version of ADT requires a SDK in version M%1$d or above.\n\nCurrent version is %2$s.\n\nPlease update your SDK to the latest version. -VersionCheck_SDK_Build_Too_Low=This version of ADT requires a SDK in version %1$d (M%2$d) or above.\n\nCurrent version is %3$s.\n\nPlease update your SDK to the latest version. -VersionCheck_Plugin_Version_Failed=Failed to get the required ADT version number from the SDK.\n\nThe Android Developer Toolkit may not work properly. -VersionCheck_Unable_To_Parse_Version_s=Unable to parse sdk build version: %1$s -VersionCheck_Plugin_Too_Old=This Android SDK requires Android Developer Toolkit version %1$d.%2$d.%3$d or above.\n\nCurrent version is %4$s.\n\nPlease update ADT to the latest version. -AdtPlugin_Failed_To_Start_s=Failed to start %1$s -AdtPlugin_Android_SDK_Content_Loader=Android SDK Content Loader -AdtPlugin_Parsing_Resources=Parsing Resources -AdtPlugin_Android_SDK_Resource_Parser=Android SDK Resource Parser -AdtPlugin_Failed_To_Parse_s=Failed to parse: diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java deleted file mode 100644 index c27c106..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2007 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.preferences; - -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.jface.preference.DirectoryFieldEditor; -import org.eclipse.jface.preference.FieldEditorPreferencePage; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPreferencePage; - -import java.io.File; - -/** - * This class represents a preference page that is contributed to the - * Preferences dialog. By subclassing <samp>FieldEditorPreferencePage</samp>, - * we can use the field support built into JFace that allows us to create a page - * that is small and knows how to save, restore and apply itself. - * <p> - * This page is used to modify preferences only. They are stored in the - * preference store that belongs to the main plug-in class. That way, - * preferences can be accessed directly via the preference store. - */ - -public class AndroidPreferencePage extends FieldEditorPreferencePage implements - IWorkbenchPreferencePage { - - public AndroidPreferencePage() { - super(GRID); - setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); - setDescription(Messages.AndroidPreferencePage_Title); - } - - /** - * Creates the field editors. Field editors are abstractions of the common - * GUI blocks needed to manipulate various types of preferences. Each field - * editor knows how to save and restore itself. - */ - @Override - public void createFieldEditors() { - - addField(new SdkDirectoryFieldEditor(AdtPlugin.PREFS_SDK_DIR, - Messages.AndroidPreferencePage_SDK_Location_, getFieldEditorParent())); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) - */ - public void init(IWorkbench workbench) { - } - - /** - * Custom version of DirectoryFieldEditor which validates that the directory really - * contains an SDK. - * - * There's a known issue here, which is really a rare edge-case: if the pref dialog is open - * which a given sdk directory and the *content* of the directory changes such that the sdk - * state changed (i.e. from valid to invalid or vice versa), the pref panel will display or - * hide the error as appropriate but the pref panel will fail to validate the apply/ok buttons - * appropriately. The easy workaround is to cancel the pref panel and enter it again. - */ - private static class SdkDirectoryFieldEditor extends DirectoryFieldEditor { - - public SdkDirectoryFieldEditor(String name, String labelText, Composite parent) { - super(name, labelText, parent); - setEmptyStringAllowed(false); - } - - /** - * Method declared on StringFieldEditor and overridden in DirectoryFieldEditor. - * Checks whether the text input field contains a valid directory. - * - * @return True if the apply/ok button should be enabled in the pref panel - */ - @Override - protected boolean doCheckState() { - String fileName = getTextControl().getText(); - fileName = fileName.trim(); - - if (fileName.indexOf(',') >= 0 || fileName.indexOf(';') >= 0) { - setErrorMessage(Messages.AndroidPreferencePage_ERROR_Reserved_Char); - return false; // Apply/OK must be disabled - } - - File file = new File(fileName); - if (!file.isDirectory()) { - setErrorMessage(JFaceResources.getString( - "DirectoryFieldEditor.errorMessage")); //$NON-NLS-1$ - return false; - } - - boolean ok = AdtPlugin.getDefault().checkSdkLocationAndId(fileName, - new AdtPlugin.CheckSdkErrorHandler() { - @Override - public boolean handleError(String message) { - setErrorMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ - return false; // Apply/OK must be disabled - } - - @Override - public boolean handleWarning(String message) { - showMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ - return true; // Apply/OK must be enabled - } - }); - if (ok) clearMessage(); - return ok; - } - - @Override - public Text getTextControl(Composite parent) { - setValidateStrategy(VALIDATE_ON_KEY_STROKE); - return super.getTextControl(parent); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java deleted file mode 100644 index e64c2f4..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2007 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.preferences; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.jarutils.DebugKeyProvider; -import com.android.jarutils.DebugKeyProvider.KeytoolException; -import com.android.prefs.AndroidLocation.AndroidLocationException; - -import org.eclipse.jface.preference.BooleanFieldEditor; -import org.eclipse.jface.preference.FieldEditorPreferencePage; -import org.eclipse.jface.preference.FileFieldEditor; -import org.eclipse.jface.preference.RadioGroupFieldEditor; -import org.eclipse.jface.preference.StringFieldEditor; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPreferencePage; - -import java.io.File; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import java.util.Date; - -/** - * Preference page for build options. - * - */ -public class BuildPreferencePage extends FieldEditorPreferencePage implements - IWorkbenchPreferencePage { - - final static String BUILD_STR_SILENT = "silent"; //$NON-NLS-1$ - final static String BUILD_STR_NORMAL = "normal"; //$NON-NLS-1$ - final static String BUILD_STR_VERBOSE = "verbose"; //$NON-NLS-1$ - - public BuildPreferencePage() { - super(GRID); - setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); - setDescription(Messages.BuildPreferencePage_Title); - } - - public static int getBuildLevel(String buildPrefValue) { - if (BUILD_STR_SILENT.equals(buildPrefValue)) { - return AdtConstants.BUILD_ALWAYS; - } else if (BUILD_STR_VERBOSE.equals(buildPrefValue)) { - return AdtConstants.BUILD_VERBOSE; - } - - return AdtConstants.BUILD_NORMAL; - } - - @Override - protected void createFieldEditors() { - addField(new BooleanFieldEditor(AdtPlugin.PREFS_RES_AUTO_REFRESH, - Messages.BuildPreferencePage_Auto_Refresh_Resources_on_Build, - getFieldEditorParent())); - - RadioGroupFieldEditor rgfe = new RadioGroupFieldEditor( - AdtPlugin.PREFS_BUILD_VERBOSITY, - Messages.BuildPreferencePage_Build_Output, 1, new String[][] { - { Messages.BuildPreferencePage_Silent, BUILD_STR_SILENT }, - { Messages.BuildPreferencePage_Normal, BUILD_STR_NORMAL }, - { Messages.BuildPreferencePage_Verbose, BUILD_STR_VERBOSE } - }, - getFieldEditorParent(), true); - addField(rgfe); - - addField(new ReadOnlyFieldEditor(AdtPlugin.PREFS_DEFAULT_DEBUG_KEYSTORE, - Messages.BuildPreferencePage_Default_KeyStore, getFieldEditorParent())); - - addField(new KeystoreFieldEditor(AdtPlugin.PREFS_CUSTOM_DEBUG_KEYSTORE, - Messages.BuildPreferencePage_Custom_Keystore, getFieldEditorParent())); - - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) - */ - public void init(IWorkbench workbench) { - } - - /** - * A read-only string field editor. - */ - private static class ReadOnlyFieldEditor extends StringFieldEditor { - - public ReadOnlyFieldEditor(String name, String labelText, Composite parent) { - super(name, labelText, parent); - } - - @Override - protected void createControl(Composite parent) { - super.createControl(parent); - - Text control = getTextControl(); - control.setEditable(false); - } - } - - /** - * Custom {@link FileFieldEditor} that checks that the keystore is valid. - */ - private static class KeystoreFieldEditor extends FileFieldEditor { - public KeystoreFieldEditor(String name, String label, Composite parent) { - super(name, label, parent); - setValidateStrategy(VALIDATE_ON_KEY_STROKE); - } - - @Override - protected boolean checkState() { - String fileName = getTextControl().getText(); - fileName = fileName.trim(); - - // empty values are considered ok. - if (fileName.length() > 0) { - File file = new File(fileName); - if (file.isFile()) { - // attempt to load the debug key. - try { - DebugKeyProvider provider = new DebugKeyProvider(fileName, - null /* storeType */, null /* key gen output */); - PrivateKey key = provider.getDebugKey(); - X509Certificate certificate = (X509Certificate)provider.getCertificate(); - - if (key == null || certificate == null) { - showErrorMessage("Unable to find debug key in keystore!"); - return false; - } - - Date today = new Date(); - if (certificate.getNotAfter().compareTo(today) < 0) { - showErrorMessage("Certificate is expired!"); - return false; - } - - if (certificate.getNotBefore().compareTo(today) > 0) { - showErrorMessage("Certificate validity is in the future!"); - return false; - } - - // we're good! - clearErrorMessage(); - return true; - } catch (GeneralSecurityException e) { - handleException(e); - return false; - } catch (IOException e) { - handleException(e); - return false; - } catch (KeytoolException e) { - handleException(e); - return false; - } catch (AndroidLocationException e) { - handleException(e); - return false; - } - - - } else { - // file does not exist. - showErrorMessage("Not a valid keystore path."); - return false; // Apply/OK must be disabled - } - } - - clearErrorMessage(); - return true; - } - - @Override - public Text getTextControl(Composite parent) { - setValidateStrategy(VALIDATE_ON_KEY_STROKE); - return super.getTextControl(parent); - } - - /** - * Set the error message from a {@link Throwable}. If the exception has no message, try - * to get the message from the cause. - * @param t the Throwable. - */ - private void handleException(Throwable t) { - String msg = t.getMessage(); - if (msg == null) { - Throwable cause = t.getCause(); - if (cause != null) { - handleException(cause); - } else { - setErrorMessage("Uknown error when getting the debug key!"); - } - - return; - } - - // valid text, display it. - showErrorMessage(msg); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/LaunchPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/LaunchPreferencePage.java deleted file mode 100644 index 8fd72c1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/LaunchPreferencePage.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008 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.preferences; - -import com.android.ide.eclipse.adt.AdtPlugin; - -import org.eclipse.jface.preference.FieldEditorPreferencePage; -import org.eclipse.jface.preference.StringFieldEditor; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPreferencePage; - -/** - * Settings page for launch related preferences. - */ -public class LaunchPreferencePage extends FieldEditorPreferencePage implements - IWorkbenchPreferencePage { - - public LaunchPreferencePage() { - super(GRID); - setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); - setDescription(Messages.LaunchPreferencePage_Title); - } - - @Override - protected void createFieldEditors() { - addField(new StringFieldEditor(AdtPlugin.PREFS_EMU_OPTIONS, - Messages.LaunchPreferencePage_Default_Emu_Options, getFieldEditorParent())); - - addField(new StringFieldEditor(AdtPlugin.PREFS_HOME_PACKAGE, - Messages.LaunchPreferencePage_Default_HOME_Package, getFieldEditorParent())); - } - - public void init(IWorkbench workbench) { - // pass - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/Messages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/Messages.java deleted file mode 100644 index e0197b9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/Messages.java +++ /dev/null @@ -1,43 +0,0 @@ - -package com.android.ide.eclipse.adt.preferences; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS { - private static final String BUNDLE_NAME = "com.android.ide.eclipse.adt.preferences.messages"; //$NON-NLS-1$ - - public static String AndroidPreferencePage_ERROR_Reserved_Char; - - public static String AndroidPreferencePage_SDK_Location_; - - public static String AndroidPreferencePage_Title; - - public static String BuildPreferencePage_Auto_Refresh_Resources_on_Build; - - public static String BuildPreferencePage_Build_Output; - - public static String BuildPreferencePage_Custom_Keystore; - - public static String BuildPreferencePage_Default_KeyStore; - - public static String BuildPreferencePage_Normal; - - public static String BuildPreferencePage_Silent; - - public static String BuildPreferencePage_Title; - - public static String BuildPreferencePage_Verbose; - - public static String LaunchPreferencePage_Default_Emu_Options; - - public static String LaunchPreferencePage_Default_HOME_Package; - - public static String LaunchPreferencePage_Title; - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/PreferenceInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/PreferenceInitializer.java deleted file mode 100644 index 2b1fb66..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/PreferenceInitializer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2007 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.preferences; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.jarutils.DebugKeyProvider; -import com.android.jarutils.DebugKeyProvider.KeytoolException; -import com.android.prefs.AndroidLocation.AndroidLocationException; - -import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; -import org.eclipse.jface.preference.IPreferenceStore; - -/** - * Class used to initialize default preference values. - */ -public class PreferenceInitializer extends AbstractPreferenceInitializer { - - /* - * (non-Javadoc) - * - * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer - * #initializeDefaultPreferences() - */ - @Override - public void initializeDefaultPreferences() { - IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - - store.setDefault(AdtPlugin.PREFS_RES_AUTO_REFRESH, true); - - store.setDefault(AdtPlugin.PREFS_BUILD_VERBOSITY, BuildPreferencePage.BUILD_STR_NORMAL); - - store.setDefault(AdtPlugin.PREFS_HOME_PACKAGE, "android.process.acore"); //$NON-NLS-1$ - - try { - store.setDefault(AdtPlugin.PREFS_DEFAULT_DEBUG_KEYSTORE, - DebugKeyProvider.getDefaultKeyStoreOsPath()); - } catch (KeytoolException e) { - AdtPlugin.log(e, "Get default debug keystore path failed"); //$NON-NLS-1$ - } catch (AndroidLocationException e) { - AdtPlugin.log(e, "Get default debug keystore path failed"); //$NON-NLS-1$ - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/messages.properties deleted file mode 100644 index 865ac19..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/messages.properties +++ /dev/null @@ -1,14 +0,0 @@ -BuildPreferencePage_Title=Build Settings: -BuildPreferencePage_Auto_Refresh_Resources_on_Build=Automatically refresh Resources and Assets folder on build -BuildPreferencePage_Build_Output=Build output -BuildPreferencePage_Silent=Silent -BuildPreferencePage_Normal=Normal -BuildPreferencePage_Verbose=Verbose -BuildPreferencePage_Default_KeyStore=Default debug keystore: -BuildPreferencePage_Custom_Keystore=Custom debug keystore: -LaunchPreferencePage_Title=Launch Settings: -LaunchPreferencePage_Default_Emu_Options=Default emulator options: -LaunchPreferencePage_Default_HOME_Package=Default HOME package: -AndroidPreferencePage_Title=Android Preferences -AndroidPreferencePage_SDK_Location_=SDK Location: -AndroidPreferencePage_ERROR_Reserved_Char=Reserved characters ',' and ';' cannot be used in the SDK Location. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/AndroidNature.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/AndroidNature.java deleted file mode 100644 index 9bcadaf..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/AndroidNature.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2007 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.project; - -import com.android.ide.eclipse.adt.build.ApkBuilder; -import com.android.ide.eclipse.adt.build.PreCompilerBuilder; -import com.android.ide.eclipse.adt.build.ResourceManagerBuilder; -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.ICommand; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IProjectNature; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.jdt.core.JavaCore; - -/** - * Project nature for the Android Projects. - */ -public class AndroidNature implements IProjectNature { - - /** the project this nature object is associated with */ - private IProject mProject; - - /** - * Configures this nature for its project. This is called by the workspace - * when natures are added to the project using - * <code>IProject.setDescription</code> and should not be called directly - * by clients. The nature extension id is added to the list of natures - * before this method is called, and need not be added here. - * - * Exceptions thrown by this method will be propagated back to the caller of - * <code>IProject.setDescription</code>, but the nature will remain in - * the project description. - * - * The Android nature adds the pre-builder and the APK builder if necessary. - * - * @see org.eclipse.core.resources.IProjectNature#configure() - * @throws CoreException if configuration fails. - */ - public void configure() throws CoreException { - configureResourceManagerBuilder(mProject); - configurePreBuilder(mProject); - configureApkBuilder(mProject); - } - - /** - * De-configures this nature for its project. This is called by the - * workspace when natures are removed from the project using - * <code>IProject.setDescription</code> and should not be called directly - * by clients. The nature extension id is removed from the list of natures - * before this method is called, and need not be removed here. - * - * Exceptions thrown by this method will be propagated back to the caller of - * <code>IProject.setDescription</code>, but the nature will still be - * removed from the project description. - * - * The Android nature removes the custom pre builder and APK builder. - * - * @see org.eclipse.core.resources.IProjectNature#deconfigure() - * @throws CoreException if configuration fails. - */ - public void deconfigure() throws CoreException { - // remove the android builders - removeBuilder(mProject, ResourceManagerBuilder.ID); - removeBuilder(mProject, PreCompilerBuilder.ID); - removeBuilder(mProject, ApkBuilder.ID); - } - - /** - * Returns the project to which this project nature applies. - * - * @return the project handle - * @see org.eclipse.core.resources.IProjectNature#getProject() - */ - public IProject getProject() { - return mProject; - } - - /** - * Sets the project to which this nature applies. Used when instantiating - * this project nature runtime. This is called by - * <code>IProject.create()</code> or - * <code>IProject.setDescription()</code> and should not be called - * directly by clients. - * - * @param project the project to which this nature applies - * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) - */ - public void setProject(IProject project) { - mProject = project; - } - - /** - * Adds the Android Nature and the Java Nature to the project if it doesn't - * already have them. - * - * @param project An existing or new project to update - * @param monitor An optional progress monitor. Can be null. - * @throws CoreException if fails to change the nature. - */ - public static synchronized void setupProjectNatures(IProject project, - IProgressMonitor monitor) throws CoreException { - if (project == null || !project.isOpen()) return; - if (monitor == null) monitor = new NullProgressMonitor(); - - // Add the natures. We need to add the Java nature first, so it adds its builder to the - // project first. This way, when the android nature is added, we can control where to put - // the android builders in relation to the java builder. - // Adding the java nature after the android one, would place the java builder before the - // android builders. - addNatureToProjectDescription(project, JavaCore.NATURE_ID, monitor); - addNatureToProjectDescription(project, AndroidConstants.NATURE, monitor); - } - - /** - * Add the specified nature to the specified project. The nature is only - * added if not already present. - * <p/> - * Android Natures are always inserted at the beginning of the list of natures in order to - * have the jdt views/dialogs display the proper icon. - * - * @param project The project to modify. - * @param natureId The Id of the nature to add. - * @param monitor An existing progress monitor. - * @throws CoreException if fails to change the nature. - */ - private static void addNatureToProjectDescription(IProject project, - String natureId, IProgressMonitor monitor) throws CoreException { - if (!project.hasNature(natureId)) { - - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - String[] newNatures = new String[natures.length + 1]; - - // Android natures always come first. - if (natureId.equals(AndroidConstants.NATURE)) { - System.arraycopy(natures, 0, newNatures, 1, natures.length); - newNatures[0] = natureId; - } else { - System.arraycopy(natures, 0, newNatures, 0, natures.length); - newNatures[natures.length] = natureId; - } - - description.setNatureIds(newNatures); - project.setDescription(description, new SubProgressMonitor(monitor, 10)); - } - } - - /** - * Adds the ResourceManagerBuilder, if its not already there. It'll insert - * itself as the first builder. - * @throws CoreException - * - */ - public static void configureResourceManagerBuilder(IProject project) - throws CoreException { - // get the builder list - IProjectDescription desc = project.getDescription(); - ICommand[] commands = desc.getBuildSpec(); - - // look for the builder in case it's already there. - for (int i = 0; i < commands.length; ++i) { - if (ResourceManagerBuilder.ID.equals(commands[i].getBuilderName())) { - return; - } - } - - // it's not there, lets add it at the beginning of the builders - ICommand[] newCommands = new ICommand[commands.length + 1]; - System.arraycopy(commands, 0, newCommands, 1, commands.length); - ICommand command = desc.newCommand(); - command.setBuilderName(ResourceManagerBuilder.ID); - newCommands[0] = command; - desc.setBuildSpec(newCommands); - project.setDescription(desc, null); - } - - /** - * Adds the PreCompilerBuilder if its not already there. It'll check for - * presence of the ResourceManager and insert itself right after. - * @param project - * @throws CoreException - */ - public static void configurePreBuilder(IProject project) - throws CoreException { - // get the builder list - IProjectDescription desc = project.getDescription(); - ICommand[] commands = desc.getBuildSpec(); - - // look for the builder in case it's already there. - for (int i = 0; i < commands.length; ++i) { - if (PreCompilerBuilder.ID.equals(commands[i].getBuilderName())) { - return; - } - } - - // we need to add it after the resource manager builder. - // Let's look for it - int index = -1; - for (int i = 0; i < commands.length; ++i) { - if (ResourceManagerBuilder.ID.equals(commands[i].getBuilderName())) { - index = i; - break; - } - } - - // we're inserting after - index++; - - // do the insertion - - // copy the builders before. - ICommand[] newCommands = new ICommand[commands.length + 1]; - System.arraycopy(commands, 0, newCommands, 0, index); - - // insert the new builder - ICommand command = desc.newCommand(); - command.setBuilderName(PreCompilerBuilder.ID); - newCommands[index] = command; - - // copy the builder after - System.arraycopy(commands, index, newCommands, index + 1, commands.length-index); - - // set the new builders in the project - desc.setBuildSpec(newCommands); - project.setDescription(desc, null); - } - - public static void configureApkBuilder(IProject project) - throws CoreException { - // Add the .apk builder at the end if it's not already there - IProjectDescription desc = project.getDescription(); - ICommand[] commands = desc.getBuildSpec(); - - for (int i = 0; i < commands.length; ++i) { - if (ApkBuilder.ID.equals(commands[i].getBuilderName())) { - return; - } - } - - ICommand[] newCommands = new ICommand[commands.length + 1]; - System.arraycopy(commands, 0, newCommands, 0, commands.length); - ICommand command = desc.newCommand(); - command.setBuilderName(ApkBuilder.ID); - newCommands[commands.length] = command; - desc.setBuildSpec(newCommands); - project.setDescription(desc, null); - } - - /** - * Removes a builder from the project. - * @param project The project to remove the builder from. - * @param id The String ID of the builder to remove. - * @return true if the builder was found and removed. - * @throws CoreException - */ - public static boolean removeBuilder(IProject project, String id) throws CoreException { - IProjectDescription description = project.getDescription(); - ICommand[] commands = description.getBuildSpec(); - for (int i = 0; i < commands.length; ++i) { - if (id.equals(commands[i].getBuilderName())) { - ICommand[] newCommands = new ICommand[commands.length - 1]; - System.arraycopy(commands, 0, newCommands, 0, i); - System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1); - description.setBuildSpec(newCommands); - project.setDescription(description, null); - return true; - } - } - - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ConvertToAndroidAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ConvertToAndroidAction.java deleted file mode 100644 index ffb2535..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ConvertToAndroidAction.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2007 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; - -import java.util.Iterator; - -/** - * Converts a project created with the activity creator into an - * Android project. - */ -public class ConvertToAndroidAction implements IObjectActionDelegate { - - private ISelection mSelection; - - /* - * (non-Javadoc) - * - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - // pass - } - - /* - * (non-Javadoc) - * - * @see IActionDelegate#run(IAction) - */ - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - for (Iterator<?> it = ((IStructuredSelection)mSelection).iterator(); it.hasNext();) { - Object element = it.next(); - IProject project = null; - if (element instanceof IProject) { - project = (IProject)element; - } else if (element instanceof IAdaptable) { - project = (IProject)((IAdaptable)element).getAdapter(IProject.class); - } - if (project != null) { - convertProject(project); - } - } - } - } - - /* - * (non-Javadoc) - * - * @see IActionDelegate#selectionChanged(IAction, ISelection) - */ - public void selectionChanged(IAction action, ISelection selection) { - this.mSelection = selection; - } - - /** - * Toggles sample nature on a project - * - * @param project to have sample nature added or removed - */ - private void convertProject(final IProject project) { - new Job("Convert Project") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - if (monitor != null) { - monitor.beginTask(String.format( - "Convert %1$s to Android", project.getName()), 5); - } - - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - - // check if the project already has the android nature. - for (int i = 0; i < natures.length; ++i) { - if (AndroidConstants.NATURE.equals(natures[i])) { - // we shouldn't be here as the visibility of the item - // is dependent on the project. - return new Status(Status.WARNING, AdtPlugin.PLUGIN_ID, - "Project is already an Android project"); - } - } - - if (monitor != null) { - monitor.worked(1); - } - - String[] newNatures = new String[natures.length + 1]; - System.arraycopy(natures, 0, newNatures, 1, natures.length); - newNatures[0] = AndroidConstants.NATURE; - - // set the new nature list in the project - description.setNatureIds(newNatures); - project.setDescription(description, null); - if (monitor != null) { - monitor.worked(1); - } - - // Fix the classpath entries. - // get a java project - IJavaProject javaProject = JavaCore.create(project); - ProjectHelper.fixProjectClasspathEntries(javaProject); - if (monitor != null) { - monitor.worked(1); - } - - return Status.OK_STATUS; - } catch (JavaModelException e) { - return e.getJavaModelStatus(); - } catch (CoreException e) { - return e.getStatus(); - } finally { - if (monitor != null) { - monitor.done(); - } - } - } - }.schedule(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/CreateAidlImportAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/CreateAidlImportAction.java deleted file mode 100644 index a1b3c38..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/CreateAidlImportAction.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * Action going through all the source of a project and creating a pre-processed aidl file - * with all the custom parcelable classes. - */ -public class CreateAidlImportAction implements IObjectActionDelegate { - - private ISelection mSelection; - - public CreateAidlImportAction() { - // pass - } - - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - // pass - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) - */ - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - for (Iterator<?> it = ((IStructuredSelection)mSelection).iterator(); it.hasNext();) { - Object element = it.next(); - IProject project = null; - if (element instanceof IProject) { - project = (IProject)element; - } else if (element instanceof IAdaptable) { - project = (IProject)((IAdaptable)element).getAdapter(IProject.class); - } - if (project != null) { - final IProject fproject = project; - new Job("Aidl preprocess") { - @Override - protected IStatus run(IProgressMonitor monitor) { - return createImportFile(fproject, monitor); - } - }.schedule(); - } - } - } - } - - public void selectionChanged(IAction action, ISelection selection) { - mSelection = selection; - } - - private IStatus createImportFile(IProject project, IProgressMonitor monitor) { - try { - if (monitor != null) { - monitor.beginTask(String.format( - "Creating aid preprocess file for %1$s", project.getName()), 1); - } - - ArrayList<String> parcelables = new ArrayList<String>(); - - IJavaProject javaProject = JavaCore.create(project); - - IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); - - for (IPackageFragmentRoot root : roots) { - if (root.isArchive() == false && root.isExternal() == false) { - parsePackageFragmentRoot(root, parcelables, monitor); - } - } - - // create the file with the parcelables - if (parcelables.size() > 0) { - IPath path = project.getLocation(); - path = path.append(AndroidConstants.FN_PROJECT_AIDL); - - File f = new File(path.toOSString()); - if (f.exists() == false) { - if (f.createNewFile() == false) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Failed to create /project.aidl"); - } - } - - FileWriter fw = new FileWriter(f); - - fw.write("// This file is auto-generated by the\n"); - fw.write("// 'Create Aidl preprocess file for Parcelable classes'\n"); - fw.write("// action. Do not modify!\n\n"); - - for (String parcelable : parcelables) { - fw.write("parcelable "); //$NON-NLS-1$ - fw.write(parcelable); - fw.append(";\n"); //$NON-NLS-1$ - } - - fw.close(); - - // need to refresh the level just below the project to make sure it's being picked - // up by eclipse. - project.refreshLocal(IResource.DEPTH_ONE, monitor); - } - - if (monitor != null) { - monitor.worked(1); - monitor.done(); - } - - return Status.OK_STATUS; - } catch (JavaModelException e) { - return e.getJavaModelStatus(); - } catch (IOException e) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Failed to create /project.aidl", e); - } catch (CoreException e) { - return e.getStatus(); - } finally { - if (monitor != null) { - monitor.done(); - } - } - } - - private void parsePackageFragmentRoot(IPackageFragmentRoot root, - ArrayList<String> parcelables, IProgressMonitor monitor) throws JavaModelException { - - IJavaElement[] elements = root.getChildren(); - - for (IJavaElement element : elements) { - if (element instanceof IPackageFragment) { - ICompilationUnit[] compilationUnits = - ((IPackageFragment)element).getCompilationUnits(); - - for (ICompilationUnit unit : compilationUnits) { - IType[] types = unit.getTypes(); - - for (IType type : types) { - parseType(type, parcelables, monitor); - } - } - } - } - } - - private void parseType(IType type, ArrayList<String> parcelables, IProgressMonitor monitor) - throws JavaModelException { - // first look in this type if it somehow extends parcelable. - ITypeHierarchy typeHierarchy = type.newSupertypeHierarchy(monitor); - - IType[] superInterfaces = typeHierarchy.getAllSuperInterfaces(type); - for (IType superInterface : superInterfaces) { - if (AndroidConstants.CLASS_PARCELABLE.equals(superInterface.getFullyQualifiedName())) { - parcelables.add(type.getFullyQualifiedName()); - } - } - - // then look in inner types. - IType[] innerTypes = type.getTypes(); - - for (IType innerType : innerTypes) { - parseType(innerType, parcelables, monitor); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ExportAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ExportAction.java deleted file mode 100644 index 3d7e929..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ExportAction.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2007 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.project; - -import com.android.ide.eclipse.common.project.ExportHelper; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; - -public class ExportAction implements IObjectActionDelegate { - - private ISelection mSelection; - - /** - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - } - - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection)mSelection; - // get the unique selected item. - if (selection.size() == 1) { - Object element = selection.getFirstElement(); - - // get the project object from it. - IProject project = null; - if (element instanceof IProject) { - project = (IProject) element; - } else if (element instanceof IAdaptable) { - project = (IProject) ((IAdaptable) element).getAdapter(IProject.class); - } - - // and finally do the action - if (project != null) { - ExportHelper.exportProject(project); - } - } - } - } - - public void selectionChanged(IAction action, ISelection selection) { - this.mSelection = selection; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ExportWizardAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ExportWizardAction.java deleted file mode 100644 index 9ade490..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ExportWizardAction.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import com.android.ide.eclipse.adt.project.export.ExportWizard; - -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPart; - -public class ExportWizardAction implements IObjectActionDelegate { - - private ISelection mSelection; - private IWorkbench mWorkbench; - - /** - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - mWorkbench = targetPart.getSite().getWorkbenchWindow().getWorkbench(); - } - - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection)mSelection; - - // call the export wizard on the current selection. - ExportWizard wizard = new ExportWizard(); - wizard.init(mWorkbench, selection); - WizardDialog dialog = new WizardDialog(mWorkbench.getDisplay().getActiveShell(), - wizard); - dialog.open(); - } - } - - public void selectionChanged(IAction action, ISelection selection) { - this.mSelection = selection; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FixLaunchConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FixLaunchConfig.java deleted file mode 100644 index b8a0b0c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FixLaunchConfig.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2007 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.debug.launching.LaunchConfigDelegate; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.ILaunchConfiguration; -import org.eclipse.debug.core.ILaunchConfigurationType; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; -import org.eclipse.debug.core.ILaunchManager; -import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; - -import java.util.ArrayList; - -/** - * Class to fix the launch configuration of a project if the java package - * defined in the manifest has been changed.<br> - * This fix can be done synchronously, or asynchronously.<br> - * <code>start()</code> will start a thread that will do the fix.<br> - * <code>run()</code> will do the fix in the current thread.<br><br> - * By default, the fix first display a dialog to the user asking if he/she wants to - * do the fix. This can be overriden by calling <code>setDisplayPrompt(false)</code>. - * - */ -public class FixLaunchConfig extends Thread { - - private IProject mProject; - private String mOldPackage; - private String mNewPackage; - - private boolean mDisplayPrompt = true; - - public FixLaunchConfig(IProject project, String oldPackage, String newPackage) { - super(); - - mProject = project; - mOldPackage = oldPackage; - mNewPackage = newPackage; - } - - /** - * Set the display prompt. If true run()/start() first ask the user if he/she wants - * to fix the Launch Config - * @param displayPrompt - */ - public void setDisplayPrompt(boolean displayPrompt) { - mDisplayPrompt = displayPrompt; - } - - /** - * Fix the Launch configurations. - */ - @Override - public void run() { - - if (mDisplayPrompt) { - // ask the user if he really wants to fix the launch config - boolean res = AdtPlugin.displayPrompt( - "Launch Configuration Update", - "The package definition in the manifest changed.\nDo you want to update your Launch Configuration(s)?"); - - if (res == false) { - return; - } - } - - // get the list of config for the project - String projectName = mProject.getName(); - ILaunchConfiguration[] configs = findConfigs(mProject.getName()); - - // loop through all the config and update the package - for (ILaunchConfiguration config : configs) { - try { - // get the working copy so that we can make changes. - ILaunchConfigurationWorkingCopy copy = config.getWorkingCopy(); - - // get the attributes for the activity - String activity = config.getAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, - ""); //$NON-NLS-1$ - - // manifests can define activities that are not in the defined package, - // so we need to make sure the activity is inside the old package. - if (activity.startsWith(mOldPackage)) { - // create the new activity - activity = mNewPackage + activity.substring(mOldPackage.length()); - - // put it in the copy - copy.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, activity); - - // save the config - copy.doSave(); - } - } catch (CoreException e) { - // couldn't get the working copy. we output the error in the console - String msg = String.format("Failed to modify %1$s: %2$s", projectName, - e.getMessage()); - AdtPlugin.printErrorToConsole(mProject, msg); - } - } - - } - - /** - * Looks for and returns all existing Launch Configuration object for a - * specified project. - * @param projectName The name of the project - * @return all the ILaunchConfiguration object. If none are present, an empty array is - * returned. - */ - private static ILaunchConfiguration[] findConfigs(String projectName) { - // get the launch manager - ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager(); - - // now get the config type for our particular android type. - ILaunchConfigurationType configType = manager. - getLaunchConfigurationType(LaunchConfigDelegate.ANDROID_LAUNCH_TYPE_ID); - - // create a temp list to hold all the valid configs - ArrayList<ILaunchConfiguration> list = new ArrayList<ILaunchConfiguration>(); - - try { - ILaunchConfiguration[] configs = manager.getLaunchConfigurations(configType); - - for (ILaunchConfiguration config : configs) { - if (config.getAttribute( - IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, - "").equals(projectName)) { //$NON-NLS-1$ - list.add(config); - } - } - } catch (CoreException e) { - } - - return list.toArray(new ILaunchConfiguration[list.size()]); - - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FixProjectAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FixProjectAction.java deleted file mode 100644 index 3043818..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FixProjectAction.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2007 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.project; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.IWorkbenchWindowActionDelegate; - -import java.util.Iterator; - -/** - * Action to fix the project properties: - * <ul> - * <li>Make sure the framework archive is present with the link to the java - * doc</li> - * </ul> - */ -public class FixProjectAction implements IObjectActionDelegate { - - private ISelection mSelection; - - /** - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - } - - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - - for (Iterator<?> it = ((IStructuredSelection) mSelection).iterator(); - it.hasNext();) { - Object element = it.next(); - IProject project = null; - if (element instanceof IProject) { - project = (IProject) element; - } else if (element instanceof IAdaptable) { - project = (IProject) ((IAdaptable) element) - .getAdapter(IProject.class); - } - if (project != null) { - fixProject(project); - } - } - } - } - - public void selectionChanged(IAction action, ISelection selection) { - this.mSelection = selection; - } - - private void fixProject(final IProject project) { - new Job("Fix Project Properties") { - - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - if (monitor != null) { - monitor.beginTask("Fix Project Properties", 6); - } - - ProjectHelper.fixProject(project); - if (monitor != null) { - monitor.worked(1); - } - - // fix the nature order to have the proper project icon - ProjectHelper.fixProjectNatureOrder(project); - if (monitor != null) { - monitor.worked(1); - } - - // now we fix the builders - AndroidNature.configureResourceManagerBuilder(project); - if (monitor != null) { - monitor.worked(1); - } - - AndroidNature.configurePreBuilder(project); - if (monitor != null) { - monitor.worked(1); - } - - AndroidNature.configureApkBuilder(project); - if (monitor != null) { - monitor.worked(1); - } - - return Status.OK_STATUS; - } catch (JavaModelException e) { - return e.getJavaModelStatus(); - } catch (CoreException e) { - return e.getStatus(); - } finally { - if (monitor != null) { - monitor.done(); - } - } - } - }.schedule(); - } - - /** - * @see IWorkbenchWindowActionDelegate#init - */ - public void init(IWorkbenchWindow window) { - // pass - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java deleted file mode 100644 index 7fc3318..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IDecoration; -import org.eclipse.jface.viewers.ILabelDecorator; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ILightweightLabelDecorator; - -/** - * A {@link ILabelDecorator} associated with an org.eclipse.ui.decorators extension. - * This is used to add android icons in some special folders in the package explorer. - */ -public class FolderDecorator implements ILightweightLabelDecorator { - - private ImageDescriptor mDescriptor; - - public FolderDecorator() { - mDescriptor = AdtPlugin.getImageDescriptor("/icons/android_project.png"); - } - - public void decorate(Object element, IDecoration decoration) { - if (element instanceof IFolder) { - IFolder folder = (IFolder)element; - - // get the project and make sure this is an android project - IProject project = folder.getProject(); - - try { - if (project.hasNature(AndroidConstants.NATURE)) { - // check the folder is directly under the project. - if (folder.getParent().getType() == IResource.PROJECT) { - String name = folder.getName(); - if (name.equals(SdkConstants.FD_ASSETS)) { - decorate(decoration, " [Android assets]"); - decoration.addOverlay(mDescriptor, IDecoration.TOP_RIGHT); - } else if (name.equals(SdkConstants.FD_RESOURCES)) { - decorate(decoration, " [Android resources]"); - decoration.addOverlay(mDescriptor, IDecoration.TOP_RIGHT); - } else if (name.equals(SdkConstants.FD_NATIVE_LIBS)) { - decorate(decoration, " [Native Libraries]"); - } - } - } - } catch (CoreException e) { - // log the error - AdtPlugin.log(e, "Unable to get nature of project '%s'.", project.getName()); - } - } - } - - public void decorate(IDecoration decoration, String suffix) { - decoration.addOverlay(mDescriptor, IDecoration.TOP_RIGHT); - - // this is broken as it changes the color of the whole text, not only of the decoration. - // TODO: figure out how to change the color of the decoration only. -// decoration.addSuffix(suffix); -// ITheme theme = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme(); -// ColorRegistry registry = theme.getColorRegistry(); -// decoration.setForegroundColor(registry.get("org.eclipse.jdt.ui.ColoredLabels.decorations")); - - } - - public boolean isLabelProperty(Object element, String property) { - // at this time return false. - return false; - } - - public void addListener(ILabelProviderListener listener) { - // No state change will affect the rendering. - } - - - - public void removeListener(ILabelProviderListener listener) { - // No state change will affect the rendering. - } - - public void dispose() { - // nothind to dispose - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/NewXmlFileWizardAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/NewXmlFileWizardAction.java deleted file mode 100644 index c117b4e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/NewXmlFileWizardAction.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008 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.project; - -import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard; - -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.WizardDialog; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPart; - -public class NewXmlFileWizardAction implements IObjectActionDelegate { - - private ISelection mSelection; - private IWorkbench mWorkbench; - - /** - * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) - */ - public void setActivePart(IAction action, IWorkbenchPart targetPart) { - mWorkbench = targetPart.getSite().getWorkbenchWindow().getWorkbench(); - } - - public void run(IAction action) { - if (mSelection instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection)mSelection; - - // call the new xml file wizard on the current selection. - NewXmlFileWizard wizard = new NewXmlFileWizard(); - wizard.init(mWorkbench, selection); - WizardDialog dialog = new WizardDialog(mWorkbench.getDisplay().getActiveShell(), - wizard); - dialog.open(); - } - } - - public void selectionChanged(IAction action, ISelection selection) { - this.mSelection = selection; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java deleted file mode 100644 index cbeddd7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Copyright (C) 2007 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.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.ide.eclipse.common.project.AndroidManifestParser; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.launching.JavaRuntime; - -import java.util.ArrayList; - -/** - * Utility class to manipulate Project parameters/properties. - */ -public final class ProjectHelper { - public final static int COMPILER_COMPLIANCE_OK = 0; - public final static int COMPILER_COMPLIANCE_LEVEL = 1; - public final static int COMPILER_COMPLIANCE_SOURCE = 2; - public final static int COMPILER_COMPLIANCE_CODEGEN_TARGET = 3; - - /** - * Adds the corresponding source folder to the class path entries. - * - * @param entries The class path entries to read. A copy will be returned. - * @param new_entry The parent source folder to remove. - * @return A new class path entries array. - */ - public static IClasspathEntry[] addEntryToClasspath( - IClasspathEntry[] entries, IClasspathEntry new_entry) { - int n = entries.length; - IClasspathEntry[] newEntries = new IClasspathEntry[n + 1]; - System.arraycopy(entries, 0, newEntries, 0, n); - newEntries[n] = new_entry; - return newEntries; - } - - /** - * Remove a classpath entry from the array. - * @param entries The class path entries to read. A copy will be returned - * @param index The index to remove. - * @return A new class path entries array. - */ - public static IClasspathEntry[] removeEntryFromClasspath( - IClasspathEntry[] entries, int index) { - int n = entries.length; - IClasspathEntry[] newEntries = new IClasspathEntry[n-1]; - - // copy the entries before index - System.arraycopy(entries, 0, newEntries, 0, index); - - // copy the entries after index - System.arraycopy(entries, index + 1, newEntries, index, - entries.length - index - 1); - - return newEntries; - } - - /** - * Converts a OS specific path into a path valid for the java doc location - * attributes of a project. - * @param javaDocOSLocation The OS specific path. - * @return a valid path for the java doc location. - */ - public static String getJavaDocPath(String javaDocOSLocation) { - // first thing we do is convert the \ into / - String javaDoc = javaDocOSLocation.replaceAll("\\\\", //$NON-NLS-1$ - AndroidConstants.WS_SEP); - - // then we add file: at the beginning for unix path, and file:/ for non - // unix path - if (javaDoc.startsWith(AndroidConstants.WS_SEP)) { - return "file:" + javaDoc; //$NON-NLS-1$ - } - - return "file:/" + javaDoc; //$NON-NLS-1$ - } - - /** - * Look for a specific classpath entry by full path and return its index. - * @param entries The entry array to search in. - * @param entryPath The OS specific path of the entry. - * @param entryKind The kind of the entry. Accepted values are 0 - * (no filter), IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_PROJECT, - * IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_VARIABLE, - * and IClasspathEntry.CPE_CONTAINER - * @return the index of the found classpath entry or -1. - */ - public static int findClasspathEntryByPath(IClasspathEntry[] entries, - String entryPath, int entryKind) { - for (int i = 0 ; i < entries.length ; i++) { - IClasspathEntry entry = entries[i]; - - int kind = entry.getEntryKind(); - - if (kind == entryKind || entryKind == 0) { - // get the path - IPath path = entry.getPath(); - - String osPathString = path.toOSString(); - if (osPathString.equals(entryPath)) { - return i; - } - } - } - - // not found, return bad index. - return -1; - } - - /** - * Look for a specific classpath entry for file name only and return its - * index. - * @param entries The entry array to search in. - * @param entryName The filename of the entry. - * @param entryKind The kind of the entry. Accepted values are 0 - * (no filter), IClasspathEntry.CPE_LIBRARY, IClasspathEntry.CPE_PROJECT, - * IClasspathEntry.CPE_SOURCE, IClasspathEntry.CPE_VARIABLE, - * and IClasspathEntry.CPE_CONTAINER - * @param startIndex Index where to start the search - * @return the index of the found classpath entry or -1. - */ - public static int findClasspathEntryByName(IClasspathEntry[] entries, - String entryName, int entryKind, int startIndex) { - if (startIndex < 0) { - startIndex = 0; - } - for (int i = startIndex ; i < entries.length ; i++) { - IClasspathEntry entry = entries[i]; - - int kind = entry.getEntryKind(); - - if (kind == entryKind || entryKind == 0) { - // get the path - IPath path = entry.getPath(); - String name = path.segment(path.segmentCount()-1); - - if (name.equals(entryName)) { - return i; - } - } - } - - // not found, return bad index. - return -1; - } - - /** - * Fix the project. This checks the SDK location. - * @param project The project to fix. - * @throws JavaModelException - */ - public static void fixProject(IProject project) throws JavaModelException { - if (AdtPlugin.getOsSdkFolder().length() == 0) { - AdtPlugin.printToConsole(project, "Unknown SDK Location, project not fixed."); - return; - } - - // get a java project - IJavaProject javaProject = JavaCore.create(project); - fixProjectClasspathEntries(javaProject); - } - - /** - * Fix the project classpath entries. The method ensures that: - * <ul> - * <li>The project does not reference any old android.zip/android.jar archive.</li> - * <li>The project does not use its output folder as a sourc folder.</li> - * <li>The project does not reference a desktop JRE</li> - * <li>The project references the AndroidClasspathContainer. - * </ul> - * @param javaProject The project to fix. - * @throws JavaModelException - */ - public static void fixProjectClasspathEntries(IJavaProject javaProject) - throws JavaModelException { - - // get the project classpath - IClasspathEntry[] entries = javaProject.getRawClasspath(); - IClasspathEntry[] oldEntries = entries; - - // check if the JRE is set as library - int jreIndex = ProjectHelper.findClasspathEntryByPath(entries, JavaRuntime.JRE_CONTAINER, - IClasspathEntry.CPE_CONTAINER); - if (jreIndex != -1) { - // the project has a JRE included, we remove it - entries = ProjectHelper.removeEntryFromClasspath(entries, jreIndex); - } - - // get the output folder - IPath outputFolder = javaProject.getOutputLocation(); - - boolean foundContainer = false; - - for (int i = 0 ; i < entries.length ;) { - // get the entry and kind - IClasspathEntry entry = entries[i]; - int kind = entry.getEntryKind(); - - if (kind == IClasspathEntry.CPE_SOURCE) { - IPath path = entry.getPath(); - - if (path.equals(outputFolder)) { - entries = ProjectHelper.removeEntryFromClasspath(entries, i); - - // continue, to skip the i++; - continue; - } - } else if (kind == IClasspathEntry.CPE_CONTAINER) { - if (AndroidClasspathContainerInitializer.checkPath(entry.getPath())) { - foundContainer = true; - } - } - - i++; - } - - // if the framework container is not there, we add it - if (foundContainer == false) { - // add the android container to the array - entries = ProjectHelper.addEntryToClasspath(entries, - AndroidClasspathContainerInitializer.getContainerEntry()); - } - - // set the new list of entries to the project - if (entries != oldEntries) { - javaProject.setRawClasspath(entries, new NullProgressMonitor()); - } - - // If needed, check and fix compiler compliance and source compatibility - ProjectHelper.checkAndFixCompilerCompliance(javaProject); - } - /** - * Checks the project compiler compliance level is supported. - * @param javaProject The project to check - * @return <ul> - * <li><code>COMPILER_COMPLIANCE_OK</code> if the project is properly configured</li> - * <li><code>COMPILER_COMPLIANCE_LEVEL</code> for unsupported compiler level</li> - * <li><code>COMPILER_COMPLIANCE_SOURCE</code> for unsupported source compatibility</li> - * <li><code>COMPILER_COMPLIANCE_CODEGEN_TARGET</code> for unsupported .class format</li> - * </ul> - */ - public static final int checkCompilerCompliance(IJavaProject javaProject) { - // get the project compliance level option - String compliance = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); - - // check it against a list of valid compliance level strings. - if (checkCompliance(compliance) == false) { - // if we didn't find the proper compliance level, we return an error - return COMPILER_COMPLIANCE_LEVEL; - } - - // otherwise we check source compatibility - String source = javaProject.getOption(JavaCore.COMPILER_SOURCE, true); - - // check it against a list of valid compliance level strings. - if (checkCompliance(source) == false) { - // if we didn't find the proper compliance level, we return an error - return COMPILER_COMPLIANCE_SOURCE; - } - - // otherwise check codegen level - String codeGen = javaProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true); - - // check it against a list of valid compliance level strings. - if (checkCompliance(codeGen) == false) { - // if we didn't find the proper compliance level, we return an error - return COMPILER_COMPLIANCE_CODEGEN_TARGET; - } - - return COMPILER_COMPLIANCE_OK; - } - - /** - * Checks the project compiler compliance level is supported. - * @param project The project to check - * @return <ul> - * <li><code>COMPILER_COMPLIANCE_OK</code> if the project is properly configured</li> - * <li><code>COMPILER_COMPLIANCE_LEVEL</code> for unsupported compiler level</li> - * <li><code>COMPILER_COMPLIANCE_SOURCE</code> for unsupported source compatibility</li> - * <li><code>COMPILER_COMPLIANCE_CODEGEN_TARGET</code> for unsupported .class format</li> - * </ul> - */ - public static final int checkCompilerCompliance(IProject project) { - // get the java project from the IProject resource object - IJavaProject javaProject = JavaCore.create(project); - - // check and return the result. - return checkCompilerCompliance(javaProject); - } - - - /** - * Checks, and fixes if needed, the compiler compliance level, and the source compatibility - * level - * @param project The project to check and fix. - */ - public static final void checkAndFixCompilerCompliance(IProject project) { - // get the java project from the IProject resource object - IJavaProject javaProject = JavaCore.create(project); - - // Now we check the compiler compliance level and make sure it is valid - checkAndFixCompilerCompliance(javaProject); - } - - /** - * Checks, and fixes if needed, the compiler compliance level, and the source compatibility - * level - * @param javaProject The Java project to check and fix. - */ - public static final void checkAndFixCompilerCompliance(IJavaProject javaProject) { - if (checkCompilerCompliance(javaProject) != COMPILER_COMPLIANCE_OK) { - // setup the preferred compiler compliance level. - javaProject.setOption(JavaCore.COMPILER_COMPLIANCE, - AndroidConstants.COMPILER_COMPLIANCE_PREFERRED); - javaProject.setOption(JavaCore.COMPILER_SOURCE, - AndroidConstants.COMPILER_COMPLIANCE_PREFERRED); - javaProject.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, - AndroidConstants.COMPILER_COMPLIANCE_PREFERRED); - - // clean the project to make sure we recompile - try { - javaProject.getProject().build(IncrementalProjectBuilder.CLEAN_BUILD, - new NullProgressMonitor()); - } catch (CoreException e) { - AdtPlugin.printErrorToConsole(javaProject.getProject(), - "Project compiler settings changed. Clean your project."); - } - } - } - - /** - * Returns a {@link IProject} by its running application name, as it returned by the AVD. - * <p/> - * <var>applicationName</var> will in most case be the package declared in the manifest, but - * can, in some cases, be a custom process name declared in the manifest, in the - * <code>application</code>, <code>activity</code>, <code>receiver</code>, or - * <code>service</code> nodes. - * @param applicationName The application name. - * @return a project or <code>null</code> if no matching project were found. - */ - public static IProject findAndroidProjectByAppName(String applicationName) { - // Get the list of project for the current workspace - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IProject[] projects = workspace.getRoot().getProjects(); - - // look for a project that matches the packageName of the app - // we're trying to debug - for (IProject p : projects) { - if (p.isOpen()) { - try { - if (p.hasNature(AndroidConstants.NATURE) == false) { - // ignore non android projects - continue; - } - } catch (CoreException e) { - // failed to get the nature? skip project. - continue; - } - - AndroidManifestHelper androidManifest = new AndroidManifestHelper(p); - - // check that there is indeed a manifest file. - if (androidManifest.getManifestIFile() == null) { - // no file? skip this project. - continue; - } - - AndroidManifestParser parser = null; - try { - parser = AndroidManifestParser.parseForData( - androidManifest.getManifestIFile()); - } catch (CoreException e) { - // skip this project. - continue; - } - - String manifestPackage = parser.getPackage(); - - if (manifestPackage != null && manifestPackage.equals(applicationName)) { - // this is the project we were looking for! - return p; - } else { - // if the package and application name don't match, - // we look for other possible process names declared in the manifest. - String[] processes = parser.getProcesses(); - for (String process : processes) { - if (process.equals(applicationName)) { - return p; - } - } - } - } - } - - return null; - - } - - public static void fixProjectNatureOrder(IProject project) throws CoreException { - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - - // if the android nature is not the first one, we reorder them - if (AndroidConstants.NATURE.equals(natures[0]) == false) { - // look for the index - for (int i = 0 ; i < natures.length ; i++) { - if (AndroidConstants.NATURE.equals(natures[i])) { - // if we try to just reorder the array in one pass, this doesn't do - // anything. I guess JDT check that we are actually adding/removing nature. - // So, first we'll remove the android nature, and then add it back. - - // remove the android nature - removeNature(project, AndroidConstants.NATURE); - - // now add it back at the first index. - description = project.getDescription(); - natures = description.getNatureIds(); - - String[] newNatures = new String[natures.length + 1]; - - // first one is android - newNatures[0] = AndroidConstants.NATURE; - - // next the rest that was before the android nature - System.arraycopy(natures, 0, newNatures, 1, natures.length); - - // set the new natures - description.setNatureIds(newNatures); - project.setDescription(description, null); - - // and stop - break; - } - } - } - } - - - /** - * Removes a specific nature from a project. - * @param project The project to remove the nature from. - * @param nature The nature id to remove. - * @throws CoreException - */ - public static void removeNature(IProject project, String nature) throws CoreException { - IProjectDescription description = project.getDescription(); - String[] natures = description.getNatureIds(); - - // check if the project already has the android nature. - for (int i = 0; i < natures.length; ++i) { - if (nature.equals(natures[i])) { - String[] newNatures = new String[natures.length - 1]; - if (i > 0) { - System.arraycopy(natures, 0, newNatures, 0, i); - } - System.arraycopy(natures, i + 1, newNatures, i, natures.length - i - 1); - description.setNatureIds(newNatures); - project.setDescription(description, null); - - return; - } - } - - } - - /** - * Returns if the project has error level markers. - * @param includeReferencedProjects flag to also test the referenced projects. - * @throws CoreException - */ - public static boolean hasError(IProject project, boolean includeReferencedProjects) - throws CoreException { - IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); - if (markers != null && markers.length > 0) { - // the project has marker(s). even though they are "problem" we - // don't know their severity. so we loop on them and figure if they - // are warnings or errors - for (IMarker m : markers) { - int s = m.getAttribute(IMarker.SEVERITY, -1); - if (s == IMarker.SEVERITY_ERROR) { - return true; - } - } - } - - // test the referenced projects if needed. - if (includeReferencedProjects) { - IProject[] projects = getReferencedProjects(project); - - for (IProject p : projects) { - if (hasError(p, false)) { - return true; - } - } - } - - return false; - } - - /** - * Saves a String property into the persistent storage of a resource. - * @param resource The resource into which the string value is saved. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - public static boolean saveStringProperty(IResource resource, String propertyName, - String value) { - QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, propertyName); - - try { - resource.setPersistentProperty(qname, value); - } catch (CoreException e) { - return false; - } - - return true; - } - - /** - * Loads a String property from the persistent storage of a resource. - * @param resource The resource from which the string value is loaded. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @return the property value or null if it was not found. - */ - public static String loadStringProperty(IResource resource, String propertyName) { - QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, propertyName); - - try { - String value = resource.getPersistentProperty(qname); - return value; - } catch (CoreException e) { - return null; - } - } - - /** - * Saves a property into the persistent storage of a resource. - * @param resource The resource into which the boolean value is saved. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value the value to save - * @return true if the save succeeded. - */ - public static boolean saveBooleanProperty(IResource resource, String propertyName, - boolean value) { - return saveStringProperty(resource, propertyName, Boolean.toString(value)); - } - - /** - * Loads a boolean property from the persistent storage of the project. - * @param resource The resource from which the boolean value is loaded. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param defaultValue The default value to return if the property was not found. - * @return the property value or the default value if the property was not found. - */ - public static boolean loadBooleanProperty(IResource resource, String propertyName, - boolean defaultValue) { - String value = loadStringProperty(resource, propertyName); - if (value != null) { - return Boolean.parseBoolean(value); - } - - return defaultValue; - } - - /** - * Saves the path of a resource into the persistent storate of the project. - * @param resource The resource into which the resource path is saved. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @param value The resource to save. It's its path that is actually stored. If null, an - * empty string is stored. - * @return true if the save succeeded - */ - public static boolean saveResourceProperty(IResource resource, String propertyName, - IResource value) { - if (value != null) { - IPath iPath = value.getProjectRelativePath(); - return saveStringProperty(resource, propertyName, iPath.toString()); - } - - return saveStringProperty(resource, propertyName, ""); //$NON-NLS-1$ - } - - /** - * Loads the path of a resource from the persistent storage of the project, and returns the - * corresponding IResource object, if it exists in the same project as <code>resource</code>. - * @param resource The resource from which the resource path is loaded. - * @param propertyName the name of the property. The id of the plugin is added to this string. - * @return The corresponding IResource object (or children interface) or null - */ - public static IResource loadResourceProperty(IResource resource, String propertyName) { - String value = loadStringProperty(resource, propertyName); - - if (value != null && value.length() > 0) { - return resource.getProject().findMember(value); - } - - return null; - } - - /** - * Returns the list of referenced project that are opened and Java projects. - * @param project - * @return list of opened referenced java project. - * @throws CoreException - */ - public static IProject[] getReferencedProjects(IProject project) throws CoreException { - IProject[] projects = project.getReferencedProjects(); - - ArrayList<IProject> list = new ArrayList<IProject>(); - - for (IProject p : projects) { - if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) { - list.add(p); - } - } - - return list.toArray(new IProject[list.size()]); - } - - - /** - * Checks a Java project compiler level option against a list of supported versions. - * @param optionValue the Compiler level option. - * @return true if the option value is supproted. - */ - private static boolean checkCompliance(String optionValue) { - for (String s : AndroidConstants.COMPILER_COMPLIANCE) { - if (s != null && s.equals(optionValue)) { - return true; - } - } - - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java deleted file mode 100644 index 399eac9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (C) 2008 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.project.export; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.jarutils.KeystoreHelper; -import com.android.jarutils.SignedJarBuilder; -import com.android.jarutils.DebugKeyProvider.IKeyGenOutput; -import com.android.jarutils.DebugKeyProvider.KeytoolException; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.events.VerifyEvent; -import org.eclipse.swt.events.VerifyListener; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IExportWizard; -import org.eclipse.ui.IWorkbench; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.List; - -/** - * Export wizard to export an apk signed with a release key/certificate. - */ -public final class ExportWizard extends Wizard implements IExportWizard { - - private static final String PROJECT_LOGO_LARGE = "icons/android_large.png"; //$NON-NLS-1$ - - private static final String PAGE_PROJECT_CHECK = "Page_ProjectCheck"; //$NON-NLS-1$ - private static final String PAGE_KEYSTORE_SELECTION = "Page_KeystoreSelection"; //$NON-NLS-1$ - private static final String PAGE_KEY_CREATION = "Page_KeyCreation"; //$NON-NLS-1$ - private static final String PAGE_KEY_SELECTION = "Page_KeySelection"; //$NON-NLS-1$ - private static final String PAGE_KEY_CHECK = "Page_KeyCheck"; //$NON-NLS-1$ - - static final String PROPERTY_KEYSTORE = "keystore"; //$NON-NLS-1$ - static final String PROPERTY_ALIAS = "alias"; //$NON-NLS-1$ - static final String PROPERTY_DESTINATION = "destination"; //$NON-NLS-1$ - - /** - * Base page class for the ExportWizard page. This class add the {@link #onShow()} callback. - */ - static abstract class ExportWizardPage extends WizardPage { - - /** bit mask constant for project data change event */ - protected static final int DATA_PROJECT = 0x001; - /** bit mask constant for keystore data change event */ - protected static final int DATA_KEYSTORE = 0x002; - /** bit mask constant for key data change event */ - protected static final int DATA_KEY = 0x004; - - protected static final VerifyListener sPasswordVerifier = new VerifyListener() { - public void verifyText(VerifyEvent e) { - // verify the characters are valid for password. - int len = e.text.length(); - - // first limit to 127 characters max - if (len + ((Text)e.getSource()).getText().length() > 127) { - e.doit = false; - return; - } - - // now only take non control characters - for (int i = 0 ; i < len ; i++) { - if (e.text.charAt(i) < 32) { - e.doit = false; - return; - } - } - } - }; - - /** - * Bit mask indicating what changed while the page was hidden. - * @see #DATA_PROJECT - * @see #DATA_KEYSTORE - * @see #DATA_KEY - */ - protected int mProjectDataChanged = 0; - - ExportWizardPage(String name) { - super(name); - } - - abstract void onShow(); - - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - onShow(); - mProjectDataChanged = 0; - } - } - - final void projectDataChanged(int changeMask) { - mProjectDataChanged |= changeMask; - } - - /** - * Calls {@link #setErrorMessage(String)} and {@link #setPageComplete(boolean)} based on a - * {@link Throwable} object. - */ - protected final void onException(Throwable t) { - String message = getExceptionMessage(t); - - setErrorMessage(message); - setPageComplete(false); - } - } - - private ExportWizardPage mPages[] = new ExportWizardPage[5]; - - private IProject mProject; - - private String mKeystore; - private String mKeystorePassword; - private boolean mKeystoreCreationMode; - - private String mKeyAlias; - private String mKeyPassword; - private int mValidity; - private String mDName; - - private PrivateKey mPrivateKey; - private X509Certificate mCertificate; - - private String mDestinationPath; - private String mApkFilePath; - private String mApkFileName; - - private ExportWizardPage mKeystoreSelectionPage; - private ExportWizardPage mKeyCreationPage; - private ExportWizardPage mKeySelectionPage; - private ExportWizardPage mKeyCheckPage; - - private boolean mKeyCreationMode; - - private List<String> mExistingAliases; - - public ExportWizard() { - setHelpAvailable(false); // TODO have help - setWindowTitle("Export Android Application"); - setImageDescriptor(); - } - - @Override - public void addPages() { - addPage(mPages[0] = new ProjectCheckPage(this, PAGE_PROJECT_CHECK)); - addPage(mKeystoreSelectionPage = mPages[1] = new KeystoreSelectionPage(this, - PAGE_KEYSTORE_SELECTION)); - addPage(mKeyCreationPage = mPages[2] = new KeyCreationPage(this, PAGE_KEY_CREATION)); - addPage(mKeySelectionPage = mPages[3] = new KeySelectionPage(this, PAGE_KEY_SELECTION)); - addPage(mKeyCheckPage = mPages[4] = new KeyCheckPage(this, PAGE_KEY_CHECK)); - } - - @Override - public boolean performFinish() { - // first we make sure export is fine if the destination file already exists - File f = new File(mDestinationPath); - if (f.isFile()) { - if (AdtPlugin.displayPrompt("Export Wizard", - "File already exists. Do you want to overwrite it?") == false) { - return false; - } - } - - // save the properties - ProjectHelper.saveStringProperty(mProject, PROPERTY_KEYSTORE, mKeystore); - ProjectHelper.saveStringProperty(mProject, PROPERTY_ALIAS, mKeyAlias); - ProjectHelper.saveStringProperty(mProject, PROPERTY_DESTINATION, mDestinationPath); - - try { - if (mKeystoreCreationMode || mKeyCreationMode) { - final ArrayList<String> output = new ArrayList<String>(); - if (KeystoreHelper.createNewStore( - mKeystore, - null /*storeType*/, - mKeystorePassword, - mKeyAlias, - mKeyPassword, - mDName, - mValidity, - new IKeyGenOutput() { - public void err(String message) { - output.add(message); - } - public void out(String message) { - output.add(message); - } - }) == false) { - // keystore creation error! - displayError(output.toArray(new String[output.size()])); - return false; - } - - // keystore is created, now load the private key and certificate. - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - FileInputStream fis = new FileInputStream(mKeystore); - keyStore.load(fis, mKeystorePassword.toCharArray()); - fis.close(); - PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry( - mKeyAlias, new KeyStore.PasswordProtection(mKeyPassword.toCharArray())); - - if (entry != null) { - mPrivateKey = entry.getPrivateKey(); - mCertificate = (X509Certificate)entry.getCertificate(); - } else { - // this really shouldn't happen since we now let the user choose the key - // from a list read from the store. - displayError("Could not find key"); - return false; - } - } - - // check the private key/certificate again since it may have been created just above. - if (mPrivateKey != null && mCertificate != null) { - FileOutputStream fos = new FileOutputStream(mDestinationPath); - SignedJarBuilder builder = new SignedJarBuilder(fos, mPrivateKey, mCertificate); - - // get the input file. - FileInputStream fis = new FileInputStream(mApkFilePath); - try { - builder.writeZip(fis, null /* filter */); - } finally { - fis.close(); - } - - builder.close(); - fos.close(); - - return true; - } - } catch (FileNotFoundException e) { - displayError(e); - } catch (NoSuchAlgorithmException e) { - displayError(e); - } catch (IOException e) { - displayError(e); - } catch (GeneralSecurityException e) { - displayError(e); - } catch (KeytoolException e) { - displayError(e); - } - - return false; - } - - @Override - public boolean canFinish() { - // check if we have the apk to resign, the destination location, and either - // a private key/certificate or the creation mode. In creation mode, unless - // all the key/keystore info is valid, the user cannot reach the last page, so there's - // no need to check them again here. - return mApkFilePath != null && - ((mPrivateKey != null && mCertificate != null) - || mKeystoreCreationMode || mKeyCreationMode) && - mDestinationPath != null; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.IWorkbenchWizard#init(org.eclipse.ui.IWorkbench, org.eclipse.jface.viewers.IStructuredSelection) - */ - public void init(IWorkbench workbench, IStructuredSelection selection) { - // get the project from the selection - Object selected = selection.getFirstElement(); - - if (selected instanceof IProject) { - mProject = (IProject)selected; - } else if (selected instanceof IAdaptable) { - IResource r = (IResource)((IAdaptable)selected).getAdapter(IResource.class); - if (r != null) { - mProject = r.getProject(); - } - } - } - - ExportWizardPage getKeystoreSelectionPage() { - return mKeystoreSelectionPage; - } - - ExportWizardPage getKeyCreationPage() { - return mKeyCreationPage; - } - - ExportWizardPage getKeySelectionPage() { - return mKeySelectionPage; - } - - ExportWizardPage getKeyCheckPage() { - return mKeyCheckPage; - } - - /** - * Returns an image descriptor for the wizard logo. - */ - private void setImageDescriptor() { - ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - } - - IProject getProject() { - return mProject; - } - - void setProject(IProject project, String apkFilePath, String filename) { - mProject = project; - mApkFilePath = apkFilePath; - mApkFileName = filename; - - updatePageOnChange(ExportWizardPage.DATA_PROJECT); - } - - String getApkFilename() { - return mApkFileName; - } - - void setKeystore(String path) { - mKeystore = path; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEYSTORE); - } - - String getKeystore() { - return mKeystore; - } - - void setKeystoreCreationMode(boolean createStore) { - mKeystoreCreationMode = createStore; - updatePageOnChange(ExportWizardPage.DATA_KEYSTORE); - } - - boolean getKeystoreCreationMode() { - return mKeystoreCreationMode; - } - - - void setKeystorePassword(String password) { - mKeystorePassword = password; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEYSTORE); - } - - String getKeystorePassword() { - return mKeystorePassword; - } - - void setKeyCreationMode(boolean createKey) { - mKeyCreationMode = createKey; - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - boolean getKeyCreationMode() { - return mKeyCreationMode; - } - - void setExistingAliases(List<String> aliases) { - mExistingAliases = aliases; - } - - List<String> getExistingAliases() { - return mExistingAliases; - } - - void setKeyAlias(String name) { - mKeyAlias = name; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - String getKeyAlias() { - return mKeyAlias; - } - - void setKeyPassword(String password) { - mKeyPassword = password; - mPrivateKey = null; - mCertificate = null; - - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - String getKeyPassword() { - return mKeyPassword; - } - - void setValidity(int validity) { - mValidity = validity; - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - int getValidity() { - return mValidity; - } - - void setDName(String dName) { - mDName = dName; - updatePageOnChange(ExportWizardPage.DATA_KEY); - } - - String getDName() { - return mDName; - } - - void setSigningInfo(PrivateKey privateKey, X509Certificate certificate) { - mPrivateKey = privateKey; - mCertificate = certificate; - } - - void setDestination(String path) { - mDestinationPath = path; - } - - void updatePageOnChange(int changeMask) { - for (ExportWizardPage page : mPages) { - page.projectDataChanged(changeMask); - } - } - - private void displayError(String... messages) { - String message = null; - if (messages.length == 1) { - message = messages[0]; - } else { - StringBuilder sb = new StringBuilder(messages[0]); - for (int i = 1; i < messages.length; i++) { - sb.append('\n'); - sb.append(messages[i]); - } - - message = sb.toString(); - } - - AdtPlugin.displayError("Export Wizard", message); - } - - private void displayError(Exception e) { - String message = getExceptionMessage(e); - displayError(message); - - AdtPlugin.log(e, "Export Wizard Error"); - } - - /** - * Returns the {@link Throwable#getMessage()}. If the {@link Throwable#getMessage()} returns - * <code>null</code>, the method is called again on the cause of the Throwable object. - * <p/>If no Throwable in the chain has a valid message, the canonical name of the first - * exception is returned. - */ - private static String getExceptionMessage(Throwable t) { - String message = t.getMessage(); - if (message == null) { - Throwable cause = t.getCause(); - if (cause != null) { - return getExceptionMessage(cause); - } - - // no more cause and still no message. display the first exception. - return t.getClass().getCanonicalName(); - } - - return message; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeyCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeyCheckPage.java deleted file mode 100644 index c64bf10..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeyCheckPage.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008 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.project.export; - -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.project.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.FormText; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Calendar; - -/** - * Final page of the wizard that checks the key and ask for the ouput location. - */ -final class KeyCheckPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private PrivateKey mPrivateKey; - private X509Certificate mCertificate; - private Text mDestination; - private boolean mFatalSigningError; - private FormText mDetailText; - - protected KeyCheckPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Destination and key/certificate checks"); - setDescription(""); // TODO - } - - public void createControl(Composite parent) { - setErrorMessage(null); - setMessage(null); - - // build the ui. - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(3, false); - gl.verticalSpacing *= 3; - composite.setLayout(gl); - - GridData gd; - - new Label(composite, SWT.NONE).setText("Destination APK file:"); - mDestination = new Text(composite, SWT.BORDER); - mDestination.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mDestination.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onDestinationChange(); - } - }); - final Button browseButton = new Button(composite, SWT.PUSH); - browseButton.setText("Browse..."); - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog = new FileDialog(browseButton.getShell(), SWT.SAVE); - - fileDialog.setText("Destination file name"); - fileDialog.setFileName(mWizard.getApkFilename()); - - String saveLocation = fileDialog.open(); - if (saveLocation != null) { - mDestination.setText(saveLocation); - } - } - }); - - mDetailText = new FormText(composite, SWT.NONE); - mDetailText.setLayoutData(gd = new GridData(GridData.FILL_BOTH)); - gd.horizontalSpan = 3; - - setControl(composite); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & DATA_PROJECT) != 0) { - // reset the destination from the content of the project - IProject project = mWizard.getProject(); - - String destination = ProjectHelper.loadStringProperty(project, - ExportWizard.PROPERTY_DESTINATION); - if (destination != null) { - mDestination.setText(destination); - } - } - - // if anything change we basically reload the data. - if (mProjectDataChanged != 0) { - mFatalSigningError = false; - - // reset the wizard with no key/cert to make it not finishable, unless a valid - // key/cert is found. - mWizard.setSigningInfo(null, null); - - if (mWizard.getKeystoreCreationMode() || mWizard.getKeyCreationMode()) { - int validity = mWizard.getValidity(); - StringBuilder sb = new StringBuilder( - String.format("<form><p>Certificate expires in %d years.</p>", - validity)); - - if (validity < 25) { - sb.append("<p>Make sure the certificate is valid for the planned lifetime of the product.</p>"); - sb.append("<p>If the certificate expires, you will be forced to sign your application with a different one.</p>"); - sb.append("<p>Applications cannot be upgraded if their certificate changes from one version to another, "); - sb.append("forcing a full uninstall/install, which will make the user lose his/her data.</p>"); - sb.append("<p>Android Market currently requires certificates to be valid until 2033.</p>"); - } - - sb.append("</form>"); - mDetailText.setText(sb.toString(), true /* parseTags */, true /* expandURLs */); - } else { - try { - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - FileInputStream fis = new FileInputStream(mWizard.getKeystore()); - keyStore.load(fis, mWizard.getKeystorePassword().toCharArray()); - fis.close(); - PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry( - mWizard.getKeyAlias(), - new KeyStore.PasswordProtection( - mWizard.getKeyPassword().toCharArray())); - - if (entry != null) { - mPrivateKey = entry.getPrivateKey(); - mCertificate = (X509Certificate)entry.getCertificate(); - } else { - setErrorMessage("Unable to find key."); - - setPageComplete(false); - } - } catch (FileNotFoundException e) { - // this was checked at the first previous step and will not happen here, unless - // the file was removed during the export wizard execution. - onException(e); - } catch (KeyStoreException e) { - onException(e); - } catch (NoSuchAlgorithmException e) { - onException(e); - } catch (UnrecoverableEntryException e) { - onException(e); - } catch (CertificateException e) { - onException(e); - } catch (IOException e) { - onException(e); - } - - if (mPrivateKey != null && mCertificate != null) { - Calendar expirationCalendar = Calendar.getInstance(); - expirationCalendar.setTime(mCertificate.getNotAfter()); - Calendar today = Calendar.getInstance(); - - if (expirationCalendar.before(today)) { - mDetailText.setText(String.format( - "<form><p>Certificate expired on %s</p></form>", - mCertificate.getNotAfter().toString()), - true /* parseTags */, true /* expandURLs */); - - // fatal error = nothing can make the page complete. - mFatalSigningError = true; - - setErrorMessage("Certificate is expired."); - setPageComplete(false); - } else { - // valid, key/cert: put it in the wizard so that it can be finished - mWizard.setSigningInfo(mPrivateKey, mCertificate); - - StringBuilder sb = new StringBuilder(String.format( - "<form><p>Certificate expires on %s.</p>", - mCertificate.getNotAfter().toString())); - - int expirationYear = expirationCalendar.get(Calendar.YEAR); - int thisYear = today.get(Calendar.YEAR); - - if (thisYear + 25 < expirationYear) { - // do nothing - } else { - if (expirationYear == thisYear) { - sb.append("<p>The certificate expires this year.</p>"); - } else { - int count = expirationYear-thisYear; - sb.append(String.format( - "<p>The Certificate expires in %1$s %2$s.</p>", - count, count == 1 ? "year" : "years")); - } - - sb.append("<p>Make sure the certificate is valid for the planned lifetime of the product.</p>"); - sb.append("<p>If the certificate expires, you will be forced to sign your application with a different one.</p>"); - sb.append("<p>Applications cannot be upgraded if their certificate changes from one version to another, "); - sb.append("forcing a full uninstall/install, which will make the user lose his/her data.</p>"); - sb.append("<p>Android Market currently requires certificates to be valid until 2033.</p>"); - } - - sb.append("</form>"); - - mDetailText.setText(sb.toString(), true /* parseTags */, true /* expandURLs */); - } - mDetailText.getParent().layout(); - } else { - // fatal error = nothing can make the page complete. - mFatalSigningError = true; - } - } - } - - onDestinationChange(); - } - - private void onDestinationChange() { - if (mFatalSigningError == false) { - // reset messages for now. - setErrorMessage(null); - setMessage(null); - - String path = mDestination.getText().trim(); - - if (path.length() == 0) { - setErrorMessage("Enter destination for the APK file."); - mWizard.setDestination(null); // this is to reset canFinish in the wizard - setPageComplete(false); - return; - } - - File file = new File(path); - if (file.isDirectory()) { - setErrorMessage("Destination is a directory."); - mWizard.setDestination(null); // this is to reset canFinish in the wizard - setPageComplete(false); - return; - } - - File parentFile = file.getParentFile(); - if (parentFile == null || parentFile.isDirectory() == false) { - setErrorMessage("Not a valid directory."); - mWizard.setDestination(null); // this is to reset canFinish in the wizard - setPageComplete(false); - return; - } - - // no error, set the destination in the wizard. - mWizard.setDestination(path); - setPageComplete(true); - - // However, we should also test if the file already exists. - if (file.isFile()) { - setMessage("Destination file already exists.", WARNING); - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeyCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeyCreationPage.java deleted file mode 100644 index d7365f7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeyCreationPage.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2008 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.project.export; - -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.project.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.VerifyEvent; -import org.eclipse.swt.events.VerifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.util.List; - -/** - * Key creation page. - */ -final class KeyCreationPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private Text mAlias; - private Text mKeyPassword; - private Text mKeyPassword2; - private Text mCnField; - private boolean mDisableOnChange = false; - private Text mOuField; - private Text mOField; - private Text mLField; - private Text mStField; - private Text mCField; - private String mDName; - private int mValidity = 0; - private List<String> mExistingAliases; - - - protected KeyCreationPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Key Creation"); - setDescription(""); // TODO? - } - - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(2, false); - composite.setLayout(gl); - - GridData gd; - - new Label(composite, SWT.NONE).setText("Alias:"); - mAlias = new Text(composite, SWT.BORDER); - mAlias.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Password:"); - mKeyPassword = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeyPassword.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeyPassword.addVerifyListener(sPasswordVerifier); - - new Label(composite, SWT.NONE).setText("Confirm:"); - mKeyPassword2 = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeyPassword2.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeyPassword2.addVerifyListener(sPasswordVerifier); - - new Label(composite, SWT.NONE).setText("Validity (years):"); - final Text validityText = new Text(composite, SWT.BORDER); - validityText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - validityText.addVerifyListener(new VerifyListener() { - public void verifyText(VerifyEvent e) { - // check for digit only. - for (int i = 0 ; i < e.text.length(); i++) { - char letter = e.text.charAt(i); - if (letter < '0' || letter > '9') { - e.doit = false; - return; - } - } - } - }); - - new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL).setLayoutData( - gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 2; - - new Label(composite, SWT.NONE).setText("First and Last Name:"); - mCnField = new Text(composite, SWT.BORDER); - mCnField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Organizational Unit:"); - mOuField = new Text(composite, SWT.BORDER); - mOuField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Organization:"); - mOField = new Text(composite, SWT.BORDER); - mOField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("City or Locality:"); - mLField = new Text(composite, SWT.BORDER); - mLField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("State or Province:"); - mStField = new Text(composite, SWT.BORDER); - mStField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - new Label(composite, SWT.NONE).setText("Country Code (XX):"); - mCField = new Text(composite, SWT.BORDER); - mCField.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - mAlias.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - mWizard.setKeyAlias(mAlias.getText().trim()); - onChange(); - } - }); - mKeyPassword.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - mWizard.setKeyPassword(mKeyPassword.getText()); - onChange(); - } - }); - mKeyPassword2.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onChange(); - } - }); - - validityText.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - try { - mValidity = Integer.parseInt(validityText.getText()); - } catch (NumberFormatException e2) { - // this should only happen if the text field is empty due to the verifyListener. - mValidity = 0; - } - mWizard.setValidity(mValidity); - onChange(); - } - }); - - ModifyListener dNameListener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - onDNameChange(); - } - }; - - mCnField.addModifyListener(dNameListener); - mOuField.addModifyListener(dNameListener); - mOField.addModifyListener(dNameListener); - mLField.addModifyListener(dNameListener); - mStField.addModifyListener(dNameListener); - mCField.addModifyListener(dNameListener); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & (DATA_PROJECT | DATA_KEYSTORE)) != 0) { - // reset the keystore/alias from the content of the project - IProject project = mWizard.getProject(); - - // disable onChange for now. we'll call it once at the end. - mDisableOnChange = true; - - String alias = ProjectHelper.loadStringProperty(project, ExportWizard.PROPERTY_ALIAS); - if (alias != null) { - mAlias.setText(alias); - } - - // get the existing list of keys if applicable - if (mWizard.getKeyCreationMode()) { - mExistingAliases = mWizard.getExistingAliases(); - } else { - mExistingAliases = null; - } - - // reset the passwords - mKeyPassword.setText(""); //$NON-NLS-1$ - mKeyPassword2.setText(""); //$NON-NLS-1$ - - // enable onChange, and call it to display errors and enable/disable pageCompleted. - mDisableOnChange = false; - onChange(); - } - } - - @Override - public IWizardPage getPreviousPage() { - if (mWizard.getKeyCreationMode()) { // this means we create a key from an existing store - return mWizard.getKeySelectionPage(); - } - - return mWizard.getKeystoreSelectionPage(); - } - - @Override - public IWizardPage getNextPage() { - return mWizard.getKeyCheckPage(); - } - - /** - * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}. - */ - private void onChange() { - if (mDisableOnChange) { - return; - } - - setErrorMessage(null); - setMessage(null); - - if (mAlias.getText().trim().length() == 0) { - setErrorMessage("Enter key alias."); - setPageComplete(false); - return; - } else if (mExistingAliases != null) { - // we cannot use indexOf, because we need to do a case-insensitive check - String keyAlias = mAlias.getText().trim(); - for (String alias : mExistingAliases) { - if (alias.equalsIgnoreCase(keyAlias)) { - setErrorMessage("Key alias already exists in keystore."); - setPageComplete(false); - return; - } - } - } - - String value = mKeyPassword.getText(); - if (value.length() == 0) { - setErrorMessage("Enter key password."); - setPageComplete(false); - return; - } else if (value.length() < 6) { - setErrorMessage("Key password is too short - must be at least 6 characters."); - setPageComplete(false); - return; - } - - if (value.equals(mKeyPassword2.getText()) == false) { - setErrorMessage("Key passwords don't match."); - setPageComplete(false); - return; - } - - if (mValidity == 0) { - setErrorMessage("Key certificate validity is required."); - setPageComplete(false); - return; - } else if (mValidity < 25) { - setMessage("A 25 year certificate validity is recommended.", WARNING); - } else if (mValidity > 1000) { - setErrorMessage("Key certificate validity must be between 1 and 1000 years."); - setPageComplete(false); - return; - } - - if (mDName == null || mDName.length() == 0) { - setErrorMessage("At least one Certificate issuer field is required to be non-empty."); - setPageComplete(false); - return; - } - - setPageComplete(true); - } - - /** - * Handles changes in the DName fields. - */ - private void onDNameChange() { - StringBuilder sb = new StringBuilder(); - - buildDName("CN", mCnField, sb); - buildDName("OU", mOuField, sb); - buildDName("O", mOField, sb); - buildDName("L", mLField, sb); - buildDName("ST", mStField, sb); - buildDName("C", mCField, sb); - - mDName = sb.toString(); - mWizard.setDName(mDName); - - onChange(); - } - - /** - * Builds the distinguished name string with the provided {@link StringBuilder}. - * @param prefix the prefix of the entry. - * @param textField The {@link Text} field containing the entry value. - * @param sb the string builder containing the dname. - */ - private void buildDName(String prefix, Text textField, StringBuilder sb) { - if (textField != null) { - String value = textField.getText().trim(); - if (value.length() > 0) { - if (sb.length() > 0) { - sb.append(","); - } - - sb.append(prefix); - sb.append('='); - sb.append(value); - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeySelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeySelectionPage.java deleted file mode 100644 index 2fcd757..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeySelectionPage.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2008 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.project.export; - -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.project.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.util.ArrayList; -import java.util.Enumeration; - -/** - * Key Selection Page. This is used when an existing keystore is used. - */ -final class KeySelectionPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private Label mKeyAliasesLabel; - private Combo mKeyAliases; - private Label mKeyPasswordLabel; - private Text mKeyPassword; - private boolean mDisableOnChange = false; - private Button mUseExistingKey; - private Button mCreateKey; - - protected KeySelectionPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Key alias selection"); - setDescription(""); // TODO - } - - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(3, false); - composite.setLayout(gl); - - GridData gd; - - mUseExistingKey = new Button(composite, SWT.RADIO); - mUseExistingKey.setText("Use existing key"); - mUseExistingKey.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - mUseExistingKey.setSelection(true); - - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = 0; - gd.widthHint = 50; - mKeyAliasesLabel = new Label(composite, SWT.NONE); - mKeyAliasesLabel.setText("Alias:"); - mKeyAliases = new Combo(composite, SWT.READ_ONLY); - mKeyAliases.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = 0; - gd.widthHint = 50; - mKeyPasswordLabel = new Label(composite, SWT.NONE); - mKeyPasswordLabel.setText("Password:"); - mKeyPassword = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeyPassword.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mCreateKey = new Button(composite, SWT.RADIO); - mCreateKey.setText("Create new key"); - mCreateKey.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - mUseExistingKey.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mWizard.setKeyCreationMode(!mUseExistingKey.getSelection()); - enableWidgets(); - onChange(); - } - }); - - mKeyAliases.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - mWizard.setKeyAlias(mKeyAliases.getItem(mKeyAliases.getSelectionIndex())); - onChange(); - } - }); - - mKeyPassword.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - mWizard.setKeyPassword(mKeyPassword.getText()); - onChange(); - } - }); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & (DATA_PROJECT | DATA_KEYSTORE)) != 0) { - // disable onChange for now. we'll call it once at the end. - mDisableOnChange = true; - - // reset the alias from the content of the project - try { - // reset to using a key - mWizard.setKeyCreationMode(false); - mUseExistingKey.setSelection(true); - mCreateKey.setSelection(false); - enableWidgets(); - - // remove the content of the alias combo always and first, in case the - // keystore password is wrong - mKeyAliases.removeAll(); - - // get the alias list (also used as a keystore password test) - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - FileInputStream fis = new FileInputStream(mWizard.getKeystore()); - keyStore.load(fis, mWizard.getKeystorePassword().toCharArray()); - fis.close(); - - Enumeration<String> aliases = keyStore.aliases(); - - // get the alias from the project previous export, and look for a match as - // we add the aliases to the combo. - IProject project = mWizard.getProject(); - - String keyAlias = ProjectHelper.loadStringProperty(project, - ExportWizard.PROPERTY_ALIAS); - - ArrayList<String> aliasList = new ArrayList<String>(); - - int selection = -1; - int count = 0; - while (aliases.hasMoreElements()) { - String alias = aliases.nextElement(); - mKeyAliases.add(alias); - aliasList.add(alias); - if (selection == -1 && alias.equalsIgnoreCase(keyAlias)) { - selection = count; - } - count++; - } - - mWizard.setExistingAliases(aliasList); - - if (selection != -1) { - mKeyAliases.select(selection); - - // since a match was found and is selected, we need to give it to - // the wizard as well - mWizard.setKeyAlias(keyAlias); - } else { - mKeyAliases.clearSelection(); - } - - // reset the password - mKeyPassword.setText(""); //$NON-NLS-1$ - - // enable onChange, and call it to display errors and enable/disable pageCompleted. - mDisableOnChange = false; - onChange(); - } catch (KeyStoreException e) { - onException(e); - } catch (FileNotFoundException e) { - onException(e); - } catch (NoSuchAlgorithmException e) { - onException(e); - } catch (CertificateException e) { - onException(e); - } catch (IOException e) { - onException(e); - } finally { - // in case we exit with an exception, we need to reset this - mDisableOnChange = false; - } - } - } - - @Override - public IWizardPage getPreviousPage() { - return mWizard.getKeystoreSelectionPage(); - } - - @Override - public IWizardPage getNextPage() { - if (mWizard.getKeyCreationMode()) { - return mWizard.getKeyCreationPage(); - } - - return mWizard.getKeyCheckPage(); - } - - /** - * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}. - */ - private void onChange() { - if (mDisableOnChange) { - return; - } - - setErrorMessage(null); - setMessage(null); - - if (mWizard.getKeyCreationMode() == false) { - if (mKeyAliases.getSelectionIndex() == -1) { - setErrorMessage("Select a key alias."); - setPageComplete(false); - return; - } - - if (mKeyPassword.getText().trim().length() == 0) { - setErrorMessage("Enter key password."); - setPageComplete(false); - return; - } - } - - setPageComplete(true); - } - - private void enableWidgets() { - boolean useKey = !mWizard.getKeyCreationMode(); - mKeyAliasesLabel.setEnabled(useKey); - mKeyAliases.setEnabled(useKey); - mKeyPassword.setEnabled(useKey); - mKeyPasswordLabel.setEnabled(useKey); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeystoreSelectionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeystoreSelectionPage.java deleted file mode 100644 index c5a4d47..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/KeystoreSelectionPage.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2008 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.project.export; - -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.project.export.ExportWizard.ExportWizardPage; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.File; - -/** - * Keystore selection page. This page allows to choose to create a new keystore or use an - * existing one. - */ -final class KeystoreSelectionPage extends ExportWizardPage { - - private final ExportWizard mWizard; - private Button mUseExistingKeystore; - private Button mCreateKeystore; - private Text mKeystore; - private Text mKeystorePassword; - private Label mConfirmLabel; - private Text mKeystorePassword2; - private boolean mDisableOnChange = false; - - protected KeystoreSelectionPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Keystore selection"); - setDescription(""); //TODO - } - - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - GridLayout gl = new GridLayout(3, false); - composite.setLayout(gl); - - GridData gd; - - mUseExistingKeystore = new Button(composite, SWT.RADIO); - mUseExistingKeystore.setText("Use existing keystore"); - mUseExistingKeystore.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - mUseExistingKeystore.setSelection(true); - - mCreateKeystore = new Button(composite, SWT.RADIO); - mCreateKeystore.setText("Create new keystore"); - mCreateKeystore.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - - new Label(composite, SWT.NONE).setText("Location:"); - mKeystore = new Text(composite, SWT.BORDER); - mKeystore.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - final Button browseButton = new Button(composite, SWT.PUSH); - browseButton.setText("Browse..."); - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - FileDialog fileDialog; - if (mUseExistingKeystore.getSelection()) { - fileDialog = new FileDialog(browseButton.getShell(),SWT.OPEN); - fileDialog.setText("Load Keystore"); - } else { - fileDialog = new FileDialog(browseButton.getShell(),SWT.SAVE); - fileDialog.setText("Select Keystore Name"); - } - - String fileName = fileDialog.open(); - if (fileName != null) { - mKeystore.setText(fileName); - } - } - }); - - new Label(composite, SWT.NONE).setText("Password:"); - mKeystorePassword = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeystorePassword.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeystorePassword.addVerifyListener(sPasswordVerifier); - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = gd.widthHint = 0; - - mConfirmLabel = new Label(composite, SWT.NONE); - mConfirmLabel.setText("Confirm:"); - mKeystorePassword2 = new Text(composite, SWT.BORDER | SWT.PASSWORD); - mKeystorePassword2.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mKeystorePassword2.addVerifyListener(sPasswordVerifier); - new Composite(composite, SWT.NONE).setLayoutData(gd = new GridData()); - gd.heightHint = gd.widthHint = 0; - mKeystorePassword2.setEnabled(false); - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - mUseExistingKeystore.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - boolean createStore = !mUseExistingKeystore.getSelection(); - mKeystorePassword2.setEnabled(createStore); - mConfirmLabel.setEnabled(createStore); - mWizard.setKeystoreCreationMode(createStore); - onChange(); - } - }); - - mKeystore.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - mWizard.setKeystore(mKeystore.getText().trim()); - onChange(); - } - }); - - mKeystorePassword.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - mWizard.setKeystorePassword(mKeystorePassword.getText()); - onChange(); - } - }); - - mKeystorePassword2.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onChange(); - } - }); - } - - @Override - public IWizardPage getNextPage() { - if (mUseExistingKeystore.getSelection()) { - return mWizard.getKeySelectionPage(); - } - - return mWizard.getKeyCreationPage(); - } - - @Override - void onShow() { - // fill the texts with information loaded from the project. - if ((mProjectDataChanged & DATA_PROJECT) != 0) { - // reset the keystore/alias from the content of the project - IProject project = mWizard.getProject(); - - // disable onChange for now. we'll call it once at the end. - mDisableOnChange = true; - - String keystore = ProjectHelper.loadStringProperty(project, - ExportWizard.PROPERTY_KEYSTORE); - if (keystore != null) { - mKeystore.setText(keystore); - } - - // reset the passwords - mKeystorePassword.setText(""); //$NON-NLS-1$ - mKeystorePassword2.setText(""); //$NON-NLS-1$ - - // enable onChange, and call it to display errors and enable/disable pageCompleted. - mDisableOnChange = false; - onChange(); - } - } - - /** - * Handles changes and update the error message and calls {@link #setPageComplete(boolean)}. - */ - private void onChange() { - if (mDisableOnChange) { - return; - } - - setErrorMessage(null); - setMessage(null); - - boolean createStore = !mUseExistingKeystore.getSelection(); - - // checks the keystore path is non null. - String keystore = mKeystore.getText().trim(); - if (keystore.length() == 0) { - setErrorMessage("Enter path to keystore."); - setPageComplete(false); - return; - } else { - File f = new File(keystore); - if (f.exists() == false) { - if (createStore == false) { - setErrorMessage("Keystore does not exist."); - setPageComplete(false); - return; - } - } else if (f.isDirectory()) { - setErrorMessage("Keystore path is a directory."); - setPageComplete(false); - return; - } else if (f.isFile()) { - if (createStore) { - setErrorMessage("File already exists."); - setPageComplete(false); - return; - } - } - } - - String value = mKeystorePassword.getText(); - if (value.length() == 0) { - setErrorMessage("Enter keystore password."); - setPageComplete(false); - return; - } else if (createStore && value.length() < 6) { - setErrorMessage("Keystore password is too short - must be at least 6 characters."); - setPageComplete(false); - return; - } - - if (createStore) { - if (mKeystorePassword2.getText().length() == 0) { - setErrorMessage("Confirm keystore password."); - setPageComplete(false); - return; - } - - if (mKeystorePassword.getText().equals(mKeystorePassword2.getText()) == false) { - setErrorMessage("Keystore passwords do not match."); - setPageComplete(false); - return; - } - } - - setPageComplete(true); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java deleted file mode 100644 index e161e18..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2008 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.project.export; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.project.export.ExportWizard.ExportWizardPage; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestParser; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.common.project.ProjectChooserHelper; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.io.File; - -/** - * First Export Wizard Page. Display warning/errors. - */ -final class ProjectCheckPage extends ExportWizardPage { - private final static String IMG_ERROR = "error.png"; //$NON-NLS-1$ - private final static String IMG_WARNING = "warning.png"; //$NON-NLS-1$ - - private final ExportWizard mWizard; - private Display mDisplay; - private Image mError; - private Image mWarning; - private boolean mHasMessage = false; - private Composite mTopComposite; - private Composite mErrorComposite; - private Text mProjectText; - private ProjectChooserHelper mProjectChooserHelper; - private boolean mFirstOnShow = true; - - protected ProjectCheckPage(ExportWizard wizard, String pageName) { - super(pageName); - mWizard = wizard; - - setTitle("Project Checks"); - setDescription("Performs a set of checks to make sure the application can be exported."); - } - - public void createControl(Composite parent) { - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); - mDisplay = parent.getDisplay(); - - GridLayout gl = null; - GridData gd = null; - - mTopComposite = new Composite(parent, SWT.NONE); - mTopComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); - mTopComposite.setLayout(new GridLayout(1, false)); - - // composite for the project selection. - Composite projectComposite = new Composite(mTopComposite, SWT.NONE); - projectComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - projectComposite.setLayout(gl = new GridLayout(3, false)); - gl.marginHeight = gl.marginWidth = 0; - - Label label = new Label(projectComposite, SWT.NONE); - label.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = 3; - label.setText("Select the project to export:"); - - new Label(projectComposite, SWT.NONE).setText("Project:"); - mProjectText = new Text(projectComposite, SWT.BORDER); - mProjectText.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - mProjectText.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - handleProjectNameChange(); - } - }); - - Button browseButton = new Button(projectComposite, SWT.PUSH); - browseButton.setText("Browse..."); - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject( - mProjectText.getText().trim()); - - if (javaProject != null) { - IProject project = javaProject.getProject(); - - // set the new name in the text field. The modify listener will take - // care of updating the status and the ExportWizard object. - mProjectText.setText(project.getName()); - } - } - }); - - setControl(mTopComposite); - } - - @Override - void onShow() { - if (mFirstOnShow) { - // get the project and init the ui - IProject project = mWizard.getProject(); - if (project != null) { - mProjectText.setText(project.getName()); - } - - mFirstOnShow = false; - } - } - - private void buildErrorUi(IProject project) { - // Show description the first time - setErrorMessage(null); - setMessage(null); - setPageComplete(true); - mHasMessage = false; - - // composite parent for the warning/error - GridLayout gl = null; - mErrorComposite = new Composite(mTopComposite, SWT.NONE); - mErrorComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - gl.verticalSpacing *= 3; // more spacing than normal. - mErrorComposite.setLayout(gl); - - if (project == null) { - setErrorMessage("Select project to export."); - mHasMessage = true; - } else { - try { - if (project.hasNature(AndroidConstants.NATURE) == false) { - addError(mErrorComposite, "Project is not an Android project."); - } else { - // check for errors - if (ProjectHelper.hasError(project, true)) { - addError(mErrorComposite, "Project has compilation error(s)"); - } - - // check the project output - IFolder outputIFolder = BaseProjectHelper.getOutputFolder(project); - if (outputIFolder != null) { - String outputOsPath = outputIFolder.getLocation().toOSString(); - String apkFilePath = outputOsPath + File.separator + project.getName() + - AndroidConstants.DOT_ANDROID_PACKAGE; - - File f = new File(apkFilePath); - if (f.isFile() == false) { - addError(mErrorComposite, - String.format("%1$s/%2$s/%1$s%3$s does not exists!", - project.getName(), - outputIFolder.getName(), - AndroidConstants.DOT_ANDROID_PACKAGE)); - } - } else { - addError(mErrorComposite, - "Unable to get the output folder of the project!"); - } - - - // project is an android project, we check the debuggable attribute. - AndroidManifestParser manifestParser = AndroidManifestParser.parse( - BaseProjectHelper.getJavaProject(project), null /* errorListener */, - true /* gatherData */, false /* markErrors */); - - Boolean debuggable = manifestParser.getDebuggable(); - - if (debuggable != null && debuggable == Boolean.TRUE) { - addWarning(mErrorComposite, - "The manifest 'debuggable' attribute is set to true.\nYou should set it to false for applications that you release to the public."); - } - - // check for mapview stuff - } - } catch (CoreException e) { - // unable to access nature - addError(mErrorComposite, "Unable to get project nature"); - } - } - - if (mHasMessage == false) { - Label label = new Label(mErrorComposite, SWT.NONE); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalSpan = 2; - label.setLayoutData(gd); - label.setText("No errors found. Click Next."); - } - - mTopComposite.layout(); - } - - /** - * Adds an error label to a {@link Composite} object. - * @param parent the Composite parent. - * @param message the error message. - */ - private void addError(Composite parent, String message) { - if (mError == null) { - mError = AdtPlugin.getImageLoader().loadImage(IMG_ERROR, mDisplay); - } - - new Label(parent, SWT.NONE).setImage(mError); - Label label = new Label(parent, SWT.NONE); - label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - label.setText(message); - - setErrorMessage("Application cannot be exported due to the error(s) below."); - setPageComplete(false); - mHasMessage = true; - } - - /** - * Adds a warning label to a {@link Composite} object. - * @param parent the Composite parent. - * @param message the warning message. - */ - private void addWarning(Composite parent, String message) { - if (mWarning == null) { - mWarning = AdtPlugin.getImageLoader().loadImage(IMG_WARNING, mDisplay); - } - - new Label(parent, SWT.NONE).setImage(mWarning); - Label label = new Label(parent, SWT.NONE); - label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - label.setText(message); - - mHasMessage = true; - } - - /** - * Checks the parameters for correctness, and update the error message and buttons. - */ - private void handleProjectNameChange() { - setPageComplete(false); - - if (mErrorComposite != null) { - mErrorComposite.dispose(); - mErrorComposite = null; - } - - // update the wizard with the new project - mWizard.setProject(null, null, null); - - //test the project name first! - String text = mProjectText.getText().trim(); - if (text.length() == 0) { - setErrorMessage("Select project to export."); - } else if (text.matches("[a-zA-Z0-9_ \\.-]+") == false) { - setErrorMessage("Project name contains unsupported characters!"); - } else { - IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null); - IProject found = null; - for (IJavaProject javaProject : projects) { - if (javaProject.getProject().getName().equals(text)) { - found = javaProject.getProject(); - break; - } - - } - - if (found != null) { - setErrorMessage(null); - - // update the wizard with the new project - setApkFilePathInWizard(found); - - // now rebuild the error ui. - buildErrorUi(found); - } else { - setErrorMessage(String.format("There is no android project named '%1$s'", - text)); - } - } - } - - private void setApkFilePathInWizard(IProject project) { - if (project != null) { - IFolder outputIFolder = BaseProjectHelper.getOutputFolder(project); - if (outputIFolder != null) { - String outputOsPath = outputIFolder.getLocation().toOSString(); - String apkFilePath = outputOsPath + File.separator + project.getName() + - AndroidConstants.DOT_ANDROID_PACKAGE; - - File f = new File(apkFilePath); - if (f.isFile()) { - mWizard.setProject(project, apkFilePath, f.getName()); - return; - } - } - } - - mWizard.setProject(null, null, null); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java deleted file mode 100644 index c7cb427..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007 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.project.internal; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; - -/** - * Classpath container for the Android projects. - */ -class AndroidClasspathContainer implements IClasspathContainer { - - private IClasspathEntry[] mClasspathEntry; - private IPath mContainerPath; - private String mName; - - /** - * Constructs the container with the {@link IClasspathEntry} representing the android - * framework jar file and the container id - * @param entries the entries representing the android framework and optional libraries. - * @param path the path containing the classpath container id. - * @param name the name of the container to display. - */ - AndroidClasspathContainer(IClasspathEntry[] entries, IPath path, String name) { - mClasspathEntry = entries; - mContainerPath = path; - mName = name; - } - - public IClasspathEntry[] getClasspathEntries() { - return mClasspathEntry; - } - - public String getDescription() { - return mName; - } - - public int getKind() { - return IClasspathContainer.K_DEFAULT_SYSTEM; - } - - public IPath getPath() { - return mContainerPath; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java deleted file mode 100644 index 339dcd0..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (C) 2007 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.project.internal; - -import com.android.ide.eclipse.adt.AdtConstants; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.LoadStatus; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.IAndroidTarget.IOptionalLibrary; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.ClasspathContainerInitializer; -import org.eclipse.jdt.core.IAccessRule; -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IClasspathContainer; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.regex.Pattern; - -/** - * Classpath container initializer responsible for binding {@link AndroidClasspathContainer} to - * {@link IProject}s. This removes the hard-coded path to the android.jar. - */ -public class AndroidClasspathContainerInitializer extends ClasspathContainerInitializer { - /** The container id for the android framework jar file */ - private final static String CONTAINER_ID = - "com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"; //$NON-NLS-1$ - - /** path separator to store multiple paths in a single property. This is guaranteed to not - * be in a path. - */ - private final static String PATH_SEPARATOR = "\u001C"; //$NON-NLS-1$ - - private final static String PROPERTY_CONTAINER_CACHE = "androidContainerCache"; //$NON-NLS-1$ - private final static String PROPERTY_TARGET_NAME = "androidTargetCache"; //$NON-NLS-1$ - private final static String CACHE_VERSION = "01"; //$NON-NLS-1$ - private final static String CACHE_VERSION_SEP = CACHE_VERSION + PATH_SEPARATOR; - - private final static int PATH_ANDROID_JAR = 0; - private final static int PATH_ANDROID_SRC = 1; - private final static int PATH_ANDROID_DOCS = 2; - private final static int PATH_ANDROID_OPT_DOCS = 3; - - public AndroidClasspathContainerInitializer() { - // pass - } - - /** - * Binds a classpath container to a {@link IClasspathContainer} for a given project, - * or silently fails if unable to do so. - * @param containerPath the container path that is the container id. - * @param project the project to bind - */ - @Override - public void initialize(IPath containerPath, IJavaProject project) throws CoreException { - if (CONTAINER_ID.equals(containerPath.toString())) { - JavaCore.setClasspathContainer(new Path(CONTAINER_ID), - new IJavaProject[] { project }, - new IClasspathContainer[] { allocateAndroidContainer(project) }, - new NullProgressMonitor()); - } - } - - /** - * Creates a new {@link IClasspathEntry} of type {@link IClasspathEntry#CPE_CONTAINER} - * linking to the Android Framework. - */ - public static IClasspathEntry getContainerEntry() { - return JavaCore.newContainerEntry(new Path(CONTAINER_ID)); - } - - /** - * Checks the {@link IPath} objects against the android framework container id and - * returns <code>true</code> if they are identical. - * @param path the <code>IPath</code> to check. - */ - public static boolean checkPath(IPath path) { - return CONTAINER_ID.equals(path.toString()); - } - - /** - * Updates the {@link IJavaProject} objects with new android framework container. This forces - * JDT to recompile them. - * @param androidProjects the projects to update. - * @return <code>true</code> if success, <code>false</code> otherwise. - */ - public static boolean updateProjects(IJavaProject[] androidProjects) { - try { - // Allocate a new AndroidClasspathContainer, and associate it to the android framework - // container id for each projects. - // By providing a new association between a container id and a IClasspathContainer, - // this forces the JDT to query the IClasspathContainer for new IClasspathEntry (with - // IClasspathContainer#getClasspathEntries()), and therefore force recompilation of - // the projects. - int projectCount = androidProjects.length; - - IClasspathContainer[] containers = new IClasspathContainer[projectCount]; - for (int i = 0 ; i < projectCount; i++) { - containers[i] = allocateAndroidContainer(androidProjects[i]); - } - - // give each project their new container in one call. - JavaCore.setClasspathContainer( - new Path(CONTAINER_ID), - androidProjects, containers, new NullProgressMonitor()); - - return true; - } catch (JavaModelException e) { - return false; - } - } - - /** - * Allocates and returns an {@link AndroidClasspathContainer} object with the proper - * path to the framework jar file. - * @param javaProject The java project that will receive the container. - */ - private static IClasspathContainer allocateAndroidContainer(IJavaProject javaProject) { - final IProject iProject = javaProject.getProject(); - - String markerMessage = null; - boolean outputToConsole = true; - - try { - AdtPlugin plugin = AdtPlugin.getDefault(); - - // get the lock object for project manipulation during SDK load. - Object lock = plugin.getSdkLockObject(); - synchronized (lock) { - boolean sdkIsLoaded = plugin.getSdkLoadStatus() == LoadStatus.LOADED; - - // check if the project has a valid target. - IAndroidTarget target = null; - if (sdkIsLoaded) { - target = Sdk.getCurrent().getTarget(iProject); - } - - // if we are loaded and the target is non null, we create a valid ClassPathContainer - if (sdkIsLoaded && target != null) { - String targetName = target.getFullName(); - - return new AndroidClasspathContainer( - createClasspathEntries(iProject, target, targetName), - new Path(CONTAINER_ID), targetName); - } - - // In case of error, we'll try different thing to provide the best error message - // possible. - // Get the project's target's hash string (if it exists) - String hashString = Sdk.getProjectTargetHashString(iProject); - - if (hashString == null || hashString.length() == 0) { - // if there is no hash string we only show this if the SDK is loaded. - // For a project opened at start-up with no target, this would be displayed - // twice, once when the project is opened, and once after the SDK has - // finished loading. - // By testing the sdk is loaded, we only show this once in the console. - if (sdkIsLoaded) { - markerMessage = String.format( - "Project has no target set. Edit the project properties to set one."); - } - } else if (sdkIsLoaded) { - markerMessage = String.format( - "Unable to resolve target '%s'", hashString); - } else { - // this is the case where there is a hashString but the SDK is not yet - // loaded and therefore we can't get the target yet. - // We check if there is a cache of the needed information. - AndroidClasspathContainer container = getContainerFromCache(iProject); - - if (container == null) { - // either the cache was wrong (ie folder does not exists anymore), or - // there was no cache. In this case we need to make sure the project - // is resolved again after the SDK is loaded. - plugin.setProjectToResolve(javaProject); - - markerMessage = String.format( - "Unable to resolve target '%s' until the SDK is loaded.", - hashString); - - // let's not log this one to the console as it will happen at every boot, - // and it's expected. (we do keep the error marker though). - outputToConsole = false; - - } else { - // we created a container from the cache, so we register the project - // to be checked for cache validity once the SDK is loaded - plugin.setProjectToCheck(javaProject); - - // and return the container - return container; - } - - } - - // return a dummy container to replace the one we may have had before. - // It'll be replaced by the real when if/when the target is resolved if/when the - // SDK finishes loading. - return new IClasspathContainer() { - public IClasspathEntry[] getClasspathEntries() { - return new IClasspathEntry[0]; - } - - public String getDescription() { - return "Unable to get system library for the project"; - } - - public int getKind() { - return IClasspathContainer.K_DEFAULT_SYSTEM; - } - - public IPath getPath() { - return null; - } - }; - } - } finally { - if (markerMessage != null) { - // log the error and put the marker on the project if we can. - if (outputToConsole) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, iProject, - markerMessage); - } - - try { - BaseProjectHelper.addMarker(iProject, AdtConstants.MARKER_TARGET, markerMessage, - -1, IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); - } catch (CoreException e) { - // In some cases, the workspace may be locked for modification when we - // pass here. - // We schedule a new job to put the marker after. - final String fmessage = markerMessage; - Job markerJob = new Job("Android SDK: Resolving error markers") { - @SuppressWarnings("unchecked") - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - BaseProjectHelper.addMarker(iProject, AdtConstants.MARKER_TARGET, - fmessage, -1, IMarker.SEVERITY_ERROR, - IMarker.PRIORITY_HIGH); - } catch (CoreException e2) { - return e2.getStatus(); - } - - return Status.OK_STATUS; - } - }; - - // build jobs are run after other interactive jobs - markerJob.setPriority(Job.BUILD); - markerJob.schedule(); - } - } else { - // no error, remove potential MARKER_TARGETs. - try { - if (iProject.exists()) { - iProject.deleteMarkers(AdtConstants.MARKER_TARGET, true, - IResource.DEPTH_INFINITE); - } - } catch (CoreException ce) { - // In some cases, the workspace may be locked for modification when we pass - // here, so we schedule a new job to put the marker after. - Job markerJob = new Job("Android SDK: Resolving error markers") { - @SuppressWarnings("unchecked") - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - iProject.deleteMarkers(AdtConstants.MARKER_TARGET, true, - IResource.DEPTH_INFINITE); - } catch (CoreException e2) { - return e2.getStatus(); - } - - return Status.OK_STATUS; - } - }; - - // build jobs are run after other interactive jobs - markerJob.setPriority(Job.BUILD); - markerJob.schedule(); - } - } - } - } - - /** - * Creates and returns an array of {@link IClasspathEntry} objects for the android - * framework and optional libraries. - * <p/>This references the OS path to the android.jar and the - * java doc directory. This is dynamically created when a project is opened, - * and never saved in the project itself, so there's no risk of storing an - * obsolete path. - * The method also stores the paths used to create the entries in the project persistent - * properties. A new {@link AndroidClasspathContainer} can be created from the stored path - * using the {@link #getContainerFromCache(IProject)} method. - * @param project - * @param target The target that contains the libraries. - * @param targetName - */ - private static IClasspathEntry[] createClasspathEntries(IProject project, - IAndroidTarget target, String targetName) { - - // get the path from the target - String[] paths = getTargetPaths(target); - - // create the classpath entry from the paths - IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths); - - // paths now contains all the path required to recreate the IClasspathEntry with no - // target info. We encode them in a single string, with each path separated by - // OS path separator. - StringBuilder sb = new StringBuilder(CACHE_VERSION); - for (String p : paths) { - sb.append(PATH_SEPARATOR); - sb.append(p); - } - - // store this in a project persistent property - ProjectHelper.saveStringProperty(project, PROPERTY_CONTAINER_CACHE, sb.toString()); - ProjectHelper.saveStringProperty(project, PROPERTY_TARGET_NAME, targetName); - - return entries; - } - - /** - * Generates an {@link AndroidClasspathContainer} from the project cache, if possible. - */ - private static AndroidClasspathContainer getContainerFromCache(IProject project) { - // get the cached info from the project persistent properties. - String cache = ProjectHelper.loadStringProperty(project, PROPERTY_CONTAINER_CACHE); - String targetNameCache = ProjectHelper.loadStringProperty(project, PROPERTY_TARGET_NAME); - if (cache == null || targetNameCache == null) { - return null; - } - - // the first 2 chars must match CACHE_VERSION. The 3rd char is the normal separator. - if (cache.startsWith(CACHE_VERSION_SEP) == false) { - return null; - } - - cache = cache.substring(CACHE_VERSION_SEP.length()); - - // the cache contains multiple paths, separated by a character guaranteed to not be in - // the path (\u001C). - // The first 3 are for android.jar (jar, source, doc), the rest are for the optional - // libraries and should contain at least one doc and a jar (if there are any libraries). - // Therefore, the path count should be 3 or 5+ - String[] paths = cache.split(Pattern.quote(PATH_SEPARATOR)); - if (paths.length < 3 || paths.length == 4) { - return null; - } - - // now we check the paths actually exist. - // There's an exception: If the source folder for android.jar does not exist, this is - // not a problem, so we skip it. - // Also paths[PATH_ANDROID_DOCS] is a URI to the javadoc, so we test it a bit differently. - try { - if (new File(paths[PATH_ANDROID_JAR]).exists() == false || - new File(new URI(paths[PATH_ANDROID_DOCS])).exists() == false) { - return null; - } - } catch (URISyntaxException e) { - return null; - } finally { - - } - - for (int i = 3 ; i < paths.length; i++) { - String path = paths[i]; - if (path.length() > 0) { - File f = new File(path); - if (f.exists() == false) { - return null; - } - } - } - - IClasspathEntry[] entries = createClasspathEntriesFromPaths(paths); - - return new AndroidClasspathContainer(entries, - new Path(CONTAINER_ID), targetNameCache); - } - - /** - * Generates an array of {@link IClasspathEntry} from a set of paths. - * @see #getTargetPaths(IAndroidTarget) - */ - private static IClasspathEntry[] createClasspathEntriesFromPaths(String[] paths) { - ArrayList<IClasspathEntry> list = new ArrayList<IClasspathEntry>(); - - // First, we create the IClasspathEntry for the framework. - // now add the android framework to the class path. - // create the path object. - IPath android_lib = new Path(paths[PATH_ANDROID_JAR]); - IPath android_src = new Path(paths[PATH_ANDROID_SRC]); - - // create the java doc link. - IClasspathAttribute cpAttribute = JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - paths[PATH_ANDROID_DOCS]); - - // create the access rule to restrict access to classes in com.android.internal - IAccessRule accessRule = JavaCore.newAccessRule( - new Path("com/android/internal/**"), //$NON-NLS-1$ - IAccessRule.K_NON_ACCESSIBLE); - - IClasspathEntry frameworkClasspathEntry = JavaCore.newLibraryEntry(android_lib, - android_src, // source attachment path - null, // default source attachment root path. - new IAccessRule[] { accessRule }, - new IClasspathAttribute[] { cpAttribute }, - false // not exported. - ); - - list.add(frameworkClasspathEntry); - - // now deal with optional libraries - if (paths.length >= 5) { - String docPath = paths[PATH_ANDROID_OPT_DOCS]; - int i = 4; - while (i < paths.length) { - Path jarPath = new Path(paths[i++]); - - IClasspathAttribute[] attributes = null; - if (docPath.length() > 0) { - attributes = new IClasspathAttribute[] { - JavaCore.newClasspathAttribute( - IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, - docPath) - }; - } - - IClasspathEntry entry = JavaCore.newLibraryEntry( - jarPath, - null, // source attachment path - null, // default source attachment root path. - null, - attributes, - false // not exported. - ); - list.add(entry); - } - } - - return list.toArray(new IClasspathEntry[list.size()]); - } - - /** - * Checks the projects' caches. If the cache was valid, the project is removed from the list. - * @param projects the list of projects to check. - */ - public static void checkProjectsCache(ArrayList<IJavaProject> projects) { - int i = 0; - projectLoop: while (i < projects.size()) { - IJavaProject javaProject = projects.get(i); - IProject iProject = javaProject.getProject(); - - // get the target from the project and its paths - IAndroidTarget target = Sdk.getCurrent().getTarget(javaProject.getProject()); - if (target == null) { - // this is really not supposed to happen. This would mean there are cached paths, - // but default.properties was deleted. Keep the project in the list to force - // a resolve which will display the error. - i++; - continue; - } - - String[] targetPaths = getTargetPaths(target); - - // now get the cached paths - String cache = ProjectHelper.loadStringProperty(iProject, PROPERTY_CONTAINER_CACHE); - if (cache == null) { - // this should not happen. We'll force resolve again anyway. - i++; - continue; - } - - String[] cachedPaths = cache.split(Pattern.quote(PATH_SEPARATOR)); - if (cachedPaths.length < 3 || cachedPaths.length == 4) { - // paths length is wrong. simply resolve the project again - i++; - continue; - } - - // Now we compare the paths. The first 4 can be compared directly. - // because of case sensitiveness we need to use File objects - - if (targetPaths.length != cachedPaths.length) { - // different paths, force resolve again. - i++; - continue; - } - - // compare the main paths (android.jar, main sources, main javadoc) - if (new File(targetPaths[PATH_ANDROID_JAR]).equals( - new File(cachedPaths[PATH_ANDROID_JAR])) == false || - new File(targetPaths[PATH_ANDROID_SRC]).equals( - new File(cachedPaths[PATH_ANDROID_SRC])) == false || - new File(targetPaths[PATH_ANDROID_DOCS]).equals( - new File(cachedPaths[PATH_ANDROID_DOCS])) == false) { - // different paths, force resolve again. - i++; - continue; - } - - if (cachedPaths.length > PATH_ANDROID_OPT_DOCS) { - // compare optional libraries javadoc - if (new File(targetPaths[PATH_ANDROID_OPT_DOCS]).equals( - new File(cachedPaths[PATH_ANDROID_OPT_DOCS])) == false) { - // different paths, force resolve again. - i++; - continue; - } - - // testing the optional jar files is a little bit trickier. - // The order is not guaranteed to be identical. - // From a previous test, we do know however that there is the same number. - // The number of libraries should be low enough that we can simply go through the - // lists manually. - targetLoop: for (int tpi = 4 ; tpi < targetPaths.length; tpi++) { - String targetPath = targetPaths[tpi]; - - // look for a match in the other array - for (int cpi = 4 ; cpi < cachedPaths.length; cpi++) { - if (new File(targetPath).equals(new File(cachedPaths[cpi]))) { - // found a match. Try the next targetPath - continue targetLoop; - } - } - - // if we stop here, we haven't found a match, which means there's a - // discrepancy in the libraries. We force a resolve. - i++; - continue projectLoop; - } - } - - // at the point the check passes, and we can remove the project from the list. - // we do not increment i in this case. - projects.remove(i); - } - } - - /** - * Returns the paths necessary to create the {@link IClasspathEntry} for this targets. - * <p/>The paths are always in the same order. - * <ul> - * <li>Path to android.jar</li> - * <li>Path to the source code for android.jar</li> - * <li>Path to the javadoc for the android platform</li> - * </ul> - * Additionally, if there are optional libraries, the array will contain: - * <ul> - * <li>Path to the librairies javadoc</li> - * <li>Path to the first .jar file</li> - * <li>(more .jar as needed)</li> - * </ul> - */ - private static String[] getTargetPaths(IAndroidTarget target) { - ArrayList<String> paths = new ArrayList<String>(); - - // first, we get the path for android.jar - // The order is: android.jar, source folder, docs folder - paths.add(target.getPath(IAndroidTarget.ANDROID_JAR)); - paths.add(target.getPath(IAndroidTarget.SOURCES)); - paths.add(AdtPlugin.getUrlDoc()); - - // now deal with optional libraries. - IOptionalLibrary[] libraries = target.getOptionalLibraries(); - if (libraries != null) { - // all the optional libraries use the same javadoc, so we start with this - String targetDocPath = target.getPath(IAndroidTarget.DOCS); - if (targetDocPath != null) { - paths.add(targetDocPath); - } else { - // we add an empty string, to always have the same count. - paths.add(""); - } - - // because different libraries could use the same jar file, we make sure we add - // each jar file only once. - HashSet<String> visitedJars = new HashSet<String>(); - for (IOptionalLibrary library : libraries) { - String jarPath = library.getJarPath(); - if (visitedJars.contains(jarPath) == false) { - visitedJars.add(jarPath); - paths.add(jarPath); - } - } - } - - return paths.toArray(new String[paths.size()]); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java deleted file mode 100644 index 584dd0d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2008 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.project.properties; - -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.sdklib.IAndroidTarget; -import com.android.sdkuilib.SdkTargetSelector; - -import org.eclipse.core.resources.IProject; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.ui.IWorkbenchPropertyPage; -import org.eclipse.ui.dialogs.PropertyPage; - -/** - * Property page for "Android" project. - * This is accessible from the Package Explorer when right clicking a project and choosing - * "Properties". - * - */ -public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPropertyPage { - - private IProject mProject; - private SdkTargetSelector mSelector; - - public AndroidPropertyPage() { - // pass - } - - @Override - protected Control createContents(Composite parent) { - // get the element (this is not yet valid in the constructor). - mProject = (IProject)getElement(); - - Composite top = new Composite(parent, SWT.NONE); - top.setLayoutData(new GridData(GridData.FILL_BOTH)); - top.setLayout(new GridLayout(1, false)); - - Label l = new Label(top, SWT.NONE); - l.setText("Project Target"); - - // get the targets from the sdk - IAndroidTarget[] targets = null; - if (Sdk.getCurrent() != null) { - targets = Sdk.getCurrent().getTargets(); - } - - // build the UI. - mSelector = new SdkTargetSelector(top, targets, false /*allowMultipleSelection*/); - - if (Sdk.getCurrent() != null) { - IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); - if (target != null) { - mSelector.setSelection(target); - } - } - - mSelector.setSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // look for the selection and validate the page if there is a selection - IAndroidTarget target = mSelector.getFirstSelected(); - setValid(target != null); - } - }); - - return top; - } - - @Override - public boolean performOk() { - if (Sdk.getCurrent() != null) { - Sdk.getCurrent().setProject(mProject, mSelector.getFirstSelected()); - } - - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java deleted file mode 100644 index 1f6ebf1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2007 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.sdk; - -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.SubMonitor; - -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import javax.management.InvalidAttributeValueException; - -/** - * Custom class loader able to load a class from the SDK jar file. - */ -public class AndroidJarLoader extends ClassLoader implements IAndroidClassLoader { - - /** - * Wrapper around a {@link Class} to provide the methods of - * {@link IAndroidClassLoader.IClassDescriptor}. - */ - public final static class ClassWrapper implements IClassDescriptor { - private Class<?> mClass; - - public ClassWrapper(Class<?> clazz) { - mClass = clazz; - } - - public String getCanonicalName() { - return mClass.getCanonicalName(); - } - - public IClassDescriptor[] getDeclaredClasses() { - Class<?>[] classes = mClass.getDeclaredClasses(); - IClassDescriptor[] iclasses = new IClassDescriptor[classes.length]; - for (int i = 0 ; i < classes.length ; i++) { - iclasses[i] = new ClassWrapper(classes[i]); - } - - return iclasses; - } - - public IClassDescriptor getEnclosingClass() { - return new ClassWrapper(mClass.getEnclosingClass()); - } - - public String getSimpleName() { - return mClass.getSimpleName(); - } - - public IClassDescriptor getSuperclass() { - return new ClassWrapper(mClass.getSuperclass()); - } - - @Override - public boolean equals(Object clazz) { - if (clazz instanceof ClassWrapper) { - return mClass.equals(((ClassWrapper)clazz).mClass); - } - return super.equals(clazz); - } - - @Override - public int hashCode() { - return mClass.hashCode(); - } - - - public boolean isInstantiable() { - int modifiers = mClass.getModifiers(); - return Modifier.isAbstract(modifiers) == false && Modifier.isPublic(modifiers) == true; - } - - public Class<?> wrappedClass() { - return mClass; - } - - } - - private String mOsFrameworkLocation; - - /** A cache for binary data extracted from the zip */ - private final HashMap<String, byte[]> mEntryCache = new HashMap<String, byte[]>(); - /** A cache for already defined Classes */ - private final HashMap<String, Class<?> > mClassCache = new HashMap<String, Class<?> >(); - - /** - * Creates the class loader by providing the os path to the framework jar archive - * - * @param osFrameworkLocation OS Path of the framework JAR file - */ - public AndroidJarLoader(String osFrameworkLocation) { - super(); - mOsFrameworkLocation = osFrameworkLocation; - } - - public String getSource() { - return mOsFrameworkLocation; - } - - /** - * Pre-loads all class binary data that belong to the given package by reading the archive - * once and caching them internally. - * <p/> - * This does not actually preload "classes", it just reads the unzipped bytes for a given - * class. To obtain a class, one must call {@link #findClass(String)} later. - * <p/> - * All classes which package name starts with "packageFilter" will be included and can be - * found later. - * <p/> - * May throw some exceptions if the framework JAR cannot be read. - * - * @param packageFilter The package that contains all the class data to preload, using a fully - * qualified binary name (.e.g "com.my.package."). The matching algorithm - * is simple "startsWith". Use an empty string to include everything. - * @param taskLabel An optional task name for the sub monitor. Can be null. - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - public void preLoadClasses(String packageFilter, String taskLabel, IProgressMonitor monitor) - throws IOException, InvalidAttributeValueException, ClassFormatError { - // Transform the package name into a zip entry path - String pathFilter = packageFilter.replaceAll("\\.", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - - SubMonitor progress = SubMonitor.convert(monitor, taskLabel == null ? "" : taskLabel, 100); - - // create streams to read the intermediary archive - FileInputStream fis = new FileInputStream(mOsFrameworkLocation); - ZipInputStream zis = new ZipInputStream(fis); - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry. - String entryPath = entry.getName(); - - if (!entryPath.endsWith(AndroidConstants.DOT_CLASS)) { - // only accept class files - continue; - } - - // check if it is part of the package to preload - if (pathFilter.length() > 0 && !entryPath.startsWith(pathFilter)) { - continue; - } - String className = entryPathToClassName(entryPath); - - if (!mEntryCache.containsKey(className)) { - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); - } - byte[] data = readZipData(zis, (int)entrySize); - mEntryCache.put(className, data); - } - - // advance 5% of whatever is allocated on the progress bar - progress.setWorkRemaining(100); - progress.worked(5); - progress.subTask(String.format("Preload %1$s", className)); - } - } - - /** - * Finds and loads all classes that derive from a given set of super classes. - * <p/> - * As a side-effect this will load and cache most, if not all, classes in the input JAR file. - * - * @param packageFilter Base name of package of classes to find. - * Use an empty string to find everyting. - * @param superClasses The super classes of all the classes to find. - * @return An hash map which keys are the super classes looked for and which values are - * ArrayList of the classes found. The array lists are always created for all the - * valid keys, they are simply empty if no deriving class is found for a given - * super class. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - public HashMap<String, ArrayList<IClassDescriptor>> findClassesDerivingFrom( - String packageFilter, - String[] superClasses) - throws IOException, InvalidAttributeValueException, ClassFormatError { - - packageFilter = packageFilter.replaceAll("\\.", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - - HashMap<String, ArrayList<IClassDescriptor>> mClassesFound = - new HashMap<String, ArrayList<IClassDescriptor>>(); - - for (String className : superClasses) { - mClassesFound.put(className, new ArrayList<IClassDescriptor>()); - } - - // create streams to read the intermediary archive - FileInputStream fis = new FileInputStream(mOsFrameworkLocation); - ZipInputStream zis = new ZipInputStream(fis); - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry and convert to a class binary name - String entryPath = entry.getName(); - if (!entryPath.endsWith(AndroidConstants.DOT_CLASS)) { - // only accept class files - continue; - } - if (packageFilter.length() > 0 && !entryPath.startsWith(packageFilter)) { - // only accept stuff from the requested root package. - continue; - } - String className = entryPathToClassName(entryPath); - - Class<?> loaded_class = mClassCache.get(className); - if (loaded_class == null) { - byte[] data = mEntryCache.get(className); - if (data == null) { - // Get the class and cache it - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); - } - data = readZipData(zis, (int)entrySize); - } - loaded_class = defineAndCacheClass(className, data); - } - - for (Class<?> superClass = loaded_class.getSuperclass(); - superClass != null; - superClass = superClass.getSuperclass()) { - String superName = superClass.getCanonicalName(); - if (mClassesFound.containsKey(superName)) { - mClassesFound.get(superName).add(new ClassWrapper(loaded_class)); - break; - } - } - } - - return mClassesFound; - } - - /** Helper method that converts a Zip entry path into a corresponding - * Java full qualified binary class name. - * <p/> - * F.ex, this converts "com/my/package/Foo.class" into "com.my.package.Foo". - */ - private String entryPathToClassName(String entryPath) { - return entryPath.replaceFirst("\\.class$", "").replaceAll("[/\\\\]", "."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - /** - * Finds the class with the specified binary name. - * - * {@inheritDoc} - */ - @Override - protected Class<?> findClass(String name) throws ClassNotFoundException { - try { - // try to find the class in the cache - Class<?> cached_class = mClassCache.get(name); - if (cached_class == ClassNotFoundException.class) { - // we already know we can't find this class, don't try again - throw new ClassNotFoundException(name); - } else if (cached_class != null) { - return cached_class; - } - - // if not found, look it up and cache it - byte[] data = loadClassData(name); - if (data != null) { - return defineAndCacheClass(name, data); - } else { - // if the class can't be found, record a CNFE class in the map so - // that we don't try to reload it next time - mClassCache.put(name, ClassNotFoundException.class); - throw new ClassNotFoundException(name); - } - } catch (ClassNotFoundException e) { - throw e; - } catch (Exception e) { - throw new ClassNotFoundException(e.getMessage()); - } - } - - /** - * Defines a class based on its binary data and caches the resulting class object. - * - * @param name The binary name of the class (i.e. package.class1$class2) - * @param data The binary data from the loader. - * @return The class defined - * @throws ClassFormatError if defineClass failed. - */ - private Class<?> defineAndCacheClass(String name, byte[] data) throws ClassFormatError { - Class<?> cached_class; - cached_class = defineClass(null, data, 0, data.length); - - if (cached_class != null) { - // Add new class to the cache class and remove it from the zip entry data cache - mClassCache.put(name, cached_class); - mEntryCache.remove(name); - } - return cached_class; - } - - /** - * Loads a class data from its binary name. - * <p/> - * This uses the class binary data that has been preloaded earlier by the preLoadClasses() - * method if possible. - * - * @param className the binary name - * @return an array of bytes representing the class data or null if not found - * @throws InvalidAttributeValueException - * @throws IOException - */ - private synchronized byte[] loadClassData(String className) - throws InvalidAttributeValueException, IOException { - - byte[] data = mEntryCache.get(className); - if (data != null) { - return data; - } - - // The name is a binary name. Something like "android.R", or "android.R$id". - // Make a path out of it. - String entryName = className.replaceAll("\\.", "/") + AndroidConstants.DOT_CLASS; //$NON-NLS-1$ //$NON-NLS-2$ - - // create streams to read the intermediary archive - FileInputStream fis = new FileInputStream(mOsFrameworkLocation); - ZipInputStream zis = new ZipInputStream(fis); - - // loop on the entries of the intermediary package and put them in the final package. - ZipEntry entry; - - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry. - String currEntryName = entry.getName(); - - if (currEntryName.equals(entryName)) { - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); - } - - data = readZipData(zis, (int)entrySize); - return data; - } - } - - return null; - } - - /** - * Reads data for the <em>current</em> entry from the zip input stream. - * - * @param zis The Zip input stream - * @param entrySize The entry size. -1 if unknown. - * @return The new data for the <em>current</em> entry. - * @throws IOException If ZipInputStream.read() fails. - */ - private byte[] readZipData(ZipInputStream zis, int entrySize) throws IOException { - int block_size = 1024; - int data_size = entrySize < 1 ? block_size : entrySize; - int offset = 0; - byte[] data = new byte[data_size]; - - while(zis.available() != 0) { - int count = zis.read(data, offset, data_size - offset); - if (count < 0) { // read data is done - break; - } - offset += count; - - if (entrySize >= 1 && offset >= entrySize) { // we know the size and we're done - break; - } - - // if we don't know the entry size and we're not done reading, - // expand the data buffer some more. - if (offset >= data_size) { - byte[] temp = new byte[data_size + block_size]; - System.arraycopy(data, 0, temp, 0, data_size); - data_size += block_size; - data = temp; - block_size *= 2; - } - } - - if (offset < data_size) { - // buffer was allocated too large, trim it - byte[] temp = new byte[offset]; - if (offset > 0) { - System.arraycopy(data, 0, temp, 0, offset); - } - data = temp; - } - - return data; - } - - /** - * Returns a {@link IAndroidClassLoader.IClassDescriptor} by its fully-qualified name. - * @param className the fully-qualified name of the class to return. - * @throws ClassNotFoundException - */ - public IClassDescriptor getClass(String className) throws ClassNotFoundException { - try { - return new ClassWrapper(loadClass(className)); - } catch (ClassNotFoundException e) { - throw e; // useful for debugging - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java deleted file mode 100644 index 2309181..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 2007 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.sdk; - -import com.android.ide.eclipse.adt.build.DexWrapper; -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.layout.descriptors.LayoutDescriptors; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.menu.descriptors.MenuDescriptors; -import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; -import com.android.ide.eclipse.editors.resources.manager.ProjectResources; -import com.android.ide.eclipse.editors.xml.descriptors.XmlDescriptors; -import com.android.layoutlib.api.ILayoutBridge; -import com.android.sdklib.IAndroidTarget; - -import java.util.Hashtable; -import java.util.Map; - -/** - * This class contains the data of an Android Target as loaded from the SDK. - */ -public class AndroidTargetData { - - public final static int DESCRIPTOR_MANIFEST = 1; - public final static int DESCRIPTOR_LAYOUT = 2; - public final static int DESCRIPTOR_MENU = 3; - public final static int DESCRIPTOR_XML = 4; - public final static int DESCRIPTOR_RESOURCES = 5; - public final static int DESCRIPTOR_SEARCHABLE = 6; - public final static int DESCRIPTOR_PREFERENCES = 7; - - public final static class LayoutBridge { - /** Link to the layout bridge */ - public ILayoutBridge bridge; - - public LoadStatus status = LoadStatus.LOADING; - - public ClassLoader classLoader; - } - - private final IAndroidTarget mTarget; - - private DexWrapper mDexWrapper; - - /** - * mAttributeValues is a map { key => list [ values ] }. - * The key for the map is "(element-xml-name,attribute-namespace:attribute-xml-local-name)". - * The attribute namespace prefix must be: - * - "android" for AndroidConstants.NS_RESOURCES - * - "xmlns" for the XMLNS URI. - * - * This is used for attributes that do not have a unique name, but still need to be populated - * with values in the UI. Uniquely named attributes have their values in {@link #mEnumValueMap}. - */ - private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>(); - - private IResourceRepository mSystemResourceRepository; - - private AndroidManifestDescriptors mManifestDescriptors; - private LayoutDescriptors mLayoutDescriptors; - private MenuDescriptors mMenuDescriptors; - private XmlDescriptors mXmlDescriptors; - - private Map<String, Map<String, Integer>> mEnumValueMap; - - private ProjectResources mFrameworkResources; - private LayoutBridge mLayoutBridge; - - private boolean mLayoutBridgeInit = false; - - AndroidTargetData(IAndroidTarget androidTarget) { - mTarget = androidTarget; - } - - void setDexWrapper(DexWrapper wrapper) { - mDexWrapper = wrapper; - } - - /** - * Creates an AndroidTargetData object. - */ - void setExtraData(IResourceRepository systemResourceRepository, - AndroidManifestDescriptors manifestDescriptors, - LayoutDescriptors layoutDescriptors, - MenuDescriptors menuDescriptors, - XmlDescriptors xmlDescriptors, - Map<String, Map<String, Integer>> enumValueMap, - String[] permissionValues, - String[] activityIntentActionValues, - String[] broadcastIntentActionValues, - String[] serviceIntentActionValues, - String[] intentCategoryValues, - ProjectResources resources, - LayoutBridge layoutBridge) { - - mSystemResourceRepository = systemResourceRepository; - mManifestDescriptors = manifestDescriptors; - mLayoutDescriptors = layoutDescriptors; - mMenuDescriptors = menuDescriptors; - mXmlDescriptors = xmlDescriptors; - mEnumValueMap = enumValueMap; - mFrameworkResources = resources; - mLayoutBridge = layoutBridge; - - setPermissions(permissionValues); - setIntentFilterActionsAndCategories(activityIntentActionValues, broadcastIntentActionValues, - serviceIntentActionValues, intentCategoryValues); - } - - public DexWrapper getDexWrapper() { - return mDexWrapper; - } - - public IResourceRepository getSystemResources() { - return mSystemResourceRepository; - } - - /** - * Returns an {@link IDescriptorProvider} from a given Id. - * The Id can be one of {@link #DESCRIPTOR_MANIFEST}, {@link #DESCRIPTOR_LAYOUT}, - * {@link #DESCRIPTOR_MENU}, or {@link #DESCRIPTOR_XML}. - * All other values will throw an {@link IllegalArgumentException}. - */ - public IDescriptorProvider getDescriptorProvider(int descriptorId) { - switch (descriptorId) { - case DESCRIPTOR_MANIFEST: - return mManifestDescriptors; - case DESCRIPTOR_LAYOUT: - return mLayoutDescriptors; - case DESCRIPTOR_MENU: - return mMenuDescriptors; - case DESCRIPTOR_XML: - return mXmlDescriptors; - case DESCRIPTOR_RESOURCES: - // FIXME: since it's hard-coded the Resources Descriptors are not platform dependent. - return ResourcesDescriptors.getInstance(); - case DESCRIPTOR_PREFERENCES: - return mXmlDescriptors.getPreferencesProvider(); - case DESCRIPTOR_SEARCHABLE: - return mXmlDescriptors.getSearchableProvider(); - default : - throw new IllegalArgumentException(); - } - } - - /** - * Returns the manifest descriptors. - */ - public AndroidManifestDescriptors getManifestDescriptors() { - return mManifestDescriptors; - } - - /** - * Returns the layout Descriptors. - */ - public LayoutDescriptors getLayoutDescriptors() { - return mLayoutDescriptors; - } - - /** - * Returns the menu descriptors. - */ - public MenuDescriptors getMenuDescriptors() { - return mMenuDescriptors; - } - - /** - * Returns the XML descriptors - */ - public XmlDescriptors getXmlDescriptors() { - return mXmlDescriptors; - } - - /** - * Returns this list of possible values for an XML attribute. - * <p/>This should only be called for attributes for which possible values depend on the - * parent element node. - * <p/>For attributes that have the same values no matter the parent node, use - * {@link #getEnumValueMap()}. - * @param elementName the name of the element containing the attribute. - * @param attributeName the name of the attribute - * @return an array of String with the possible values, or <code>null</code> if no values were - * found. - */ - public String[] getAttributeValues(String elementName, String attributeName) { - String key = String.format("(%1$s,%2$s)", elementName, attributeName); //$NON-NLS-1$ - return mAttributeValues.get(key); - } - - /** - * Returns this list of possible values for an XML attribute. - * <p/>This should only be called for attributes for which possible values depend on the - * parent and great-grand-parent element node. - * <p/>The typical example of this is for the 'name' attribute under - * activity/intent-filter/action - * <p/>For attributes that have the same values no matter the parent node, use - * {@link #getEnumValueMap()}. - * @param elementName the name of the element containing the attribute. - * @param attributeName the name of the attribute - * @param greatGrandParentElementName the great-grand-parent node. - * @return an array of String with the possible values, or <code>null</code> if no values were - * found. - */ - public String[] getAttributeValues(String elementName, String attributeName, - String greatGrandParentElementName) { - if (greatGrandParentElementName != null) { - String key = String.format("(%1$s,%2$s,%3$s)", //$NON-NLS-1$ - greatGrandParentElementName, elementName, attributeName); - String[] values = mAttributeValues.get(key); - if (values != null) { - return values; - } - } - - return getAttributeValues(elementName, attributeName); - } - - /** - * Returns the enum values map. - * <p/>The map defines the possible values for XML attributes. The key is the attribute name - * and the value is a map of (string, integer) in which the key (string) is the name of - * the value, and the Integer is the numerical value in the compiled binary XML files. - */ - public Map<String, Map<String, Integer>> getEnumValueMap() { - return mEnumValueMap; - } - - /** - * Returns the {@link ProjectResources} containing the Framework Resources. - */ - public ProjectResources getFrameworkResources() { - return mFrameworkResources; - } - - /** - * Returns a {@link LayoutBridge} object possibly containing a {@link ILayoutBridge} object. - * <p/>If {@link LayoutBridge#bridge} is <code>null</code>, {@link LayoutBridge#status} will - * contain the reason (either {@link LoadStatus#LOADING} or {@link LoadStatus#FAILED}). - * <p/>Valid {@link ILayoutBridge} objects are always initialized before being returned. - */ - public synchronized LayoutBridge getLayoutBridge() { - if (mLayoutBridgeInit == false && mLayoutBridge.bridge != null) { - mLayoutBridge.bridge.init(mTarget.getPath(IAndroidTarget.FONTS), - getEnumValueMap()); - mLayoutBridgeInit = true; - } - return mLayoutBridge; - } - - /** - * Sets the permission values - * @param permissionValues the list of permissions - */ - private void setPermissions(String[] permissionValues) { - setValues("(uses-permission,android:name)", permissionValues); //$NON-NLS-1$ - setValues("(application,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(activity,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(receiver,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(service,android:permission)", permissionValues); //$NON-NLS-1$ - setValues("(provider,android:permission)", permissionValues); //$NON-NLS-1$ - } - - private void setIntentFilterActionsAndCategories(String[] activityIntentActions, - String[] broadcastIntentActions, String[] serviceIntentActions, - String[] intentCategoryValues) { - setValues("(activity,action,android:name)", activityIntentActions); //$NON-NLS-1$ - setValues("(receiver,action,android:name)", broadcastIntentActions); //$NON-NLS-1$ - setValues("(service,action,android:name)", serviceIntentActions); //$NON-NLS-1$ - setValues("(category,android:name)", intentCategoryValues); //$NON-NLS-1$ - } - - /** - * Sets a (name, values) pair in the hash map. - * <p/> - * If the name is already present in the map, it is first removed. - * @param name the name associated with the values. - * @param values The values to add. - */ - private void setValues(String name, String[] values) { - mAttributeValues.remove(name); - mAttributeValues.put(name, values); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java deleted file mode 100644 index aab660d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.build.DexWrapper; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.AttrsXmlParser; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo; -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.common.resources.ViewClassInfo; -import com.android.ide.eclipse.editors.layout.descriptors.LayoutDescriptors; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.menu.descriptors.MenuDescriptors; -import com.android.ide.eclipse.editors.resources.manager.ProjectResources; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.xml.descriptors.XmlDescriptors; -import com.android.layoutlib.api.ILayoutBridge; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.SubMonitor; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.management.InvalidAttributeValueException; - -/** - * Parser for the platform data in an SDK. - * <p/> - * This gather the following information: - * <ul> - * <li>Resource ID from <code>android.R</code></li> - * <li>The list of permissions values from <code>android.Manifest$permission</code></li> - * <li></li> - * </ul> - */ -public final class AndroidTargetParser { - - private static final String TAG = "Framework Resource Parser"; - private final IAndroidTarget mAndroidTarget; - - /** - * Creates a platform data parser. - */ - public AndroidTargetParser(IAndroidTarget platformTarget) { - mAndroidTarget = platformTarget; - } - - /** - * Parses the framework, collects all interesting information and stores them in the - * {@link IAndroidTarget} given to the constructor. - * - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - * @return True if the SDK path was valid and parsing has been attempted. - */ - public IStatus run(IProgressMonitor monitor) { - try { - SubMonitor progress = SubMonitor.convert(monitor, - String.format("Parsing SDK %1$s", mAndroidTarget.getName()), - 200); - - AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget); - - // load DX. - DexWrapper dexWrapper = new DexWrapper(); - IStatus res = dexWrapper.loadDex(mAndroidTarget.getPath(IAndroidTarget.DX_JAR)); - if (res != Status.OK_STATUS) { - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - String.format("dx.jar loading failed for target '%1$s'", - mAndroidTarget.getFullName())); - } - - // we have loaded dx. - targetData.setDexWrapper(dexWrapper); - - // parse the rest of the data. - progress.setWorkRemaining(120); - - AndroidJarLoader classLoader = - new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR)); - - preload(classLoader, progress.newChild(40, SubMonitor.SUPPRESS_NONE)); - progress.setWorkRemaining(80); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // get the resource Ids. - progress.subTask("Resource IDs"); - IResourceRepository frameworkRepository = collectResourceIds(classLoader); - progress.worked(5); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // get the permissions - progress.subTask("Permissions"); - String[] permissionValues = collectPermissions(classLoader); - progress.worked(5); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // get the action and category values for the Intents. - progress.subTask("Intents"); - ArrayList<String> activity_actions = new ArrayList<String>(); - ArrayList<String> broadcast_actions = new ArrayList<String>(); - ArrayList<String> service_actions = new ArrayList<String>(); - ArrayList<String> categories = new ArrayList<String>(); - collectIntentFilterActionsAndCategories(activity_actions, broadcast_actions, - service_actions, categories); - progress.worked(5); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // gather the attribute definition - progress.subTask("Attributes definitions"); - AttrsXmlParser attrsXmlParser = new AttrsXmlParser( - mAndroidTarget.getPath(IAndroidTarget.ATTRIBUTES)); - attrsXmlParser.preload(); - - progress.subTask("Manifest definitions"); - AttrsXmlParser attrsManifestXmlParser = new AttrsXmlParser( - mAndroidTarget.getPath(IAndroidTarget.MANIFEST_ATTRIBUTES), - attrsXmlParser); - attrsManifestXmlParser.preload(); - - Collection<ViewClassInfo> mainList = new ArrayList<ViewClassInfo>(); - Collection<ViewClassInfo> groupList = new ArrayList<ViewClassInfo>(); - - // collect the layout/widgets classes - progress.subTask("Widgets and layouts"); - collectLayoutClasses(classLoader, attrsXmlParser, mainList, groupList, - progress.newChild(40)); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - ViewClassInfo[] layoutViewsInfo = mainList.toArray(new ViewClassInfo[mainList.size()]); - ViewClassInfo[] layoutGroupsInfo = groupList.toArray( - new ViewClassInfo[groupList.size()]); - - // collect the preferences classes. - mainList.clear(); - groupList.clear(); - collectPreferenceClasses(classLoader, attrsXmlParser, mainList, groupList, - progress.newChild(5)); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - ViewClassInfo[] preferencesInfo = mainList.toArray(new ViewClassInfo[mainList.size()]); - ViewClassInfo[] preferenceGroupsInfo = groupList.toArray( - new ViewClassInfo[groupList.size()]); - - Map<String, DeclareStyleableInfo> xmlMenuMap = collectMenuDefinitions(attrsXmlParser); - Map<String, DeclareStyleableInfo> xmlSearchableMap = collectSearchableDefinitions( - attrsXmlParser); - Map<String, DeclareStyleableInfo> manifestMap = collectManifestDefinitions( - attrsManifestXmlParser); - Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues(); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - // From the information that was collected, create the pieces that will be put in - // the PlatformData object. - AndroidManifestDescriptors manifestDescriptors = new AndroidManifestDescriptors(); - manifestDescriptors.updateDescriptors(manifestMap); - progress.worked(10); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - LayoutDescriptors layoutDescriptors = new LayoutDescriptors(); - layoutDescriptors.updateDescriptors(layoutViewsInfo, layoutGroupsInfo); - progress.worked(10); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - MenuDescriptors menuDescriptors = new MenuDescriptors(); - menuDescriptors.updateDescriptors(xmlMenuMap); - progress.worked(10); - - if (progress.isCanceled()) { - return Status.CANCEL_STATUS; - } - - XmlDescriptors xmlDescriptors = new XmlDescriptors(); - xmlDescriptors.updateDescriptors(xmlSearchableMap, preferencesInfo, - preferenceGroupsInfo); - progress.worked(10); - - // load the framework resources. - ProjectResources resources = ResourceManager.getInstance().loadFrameworkResources( - mAndroidTarget); - progress.worked(10); - - // now load the layout lib bridge - LayoutBridge layoutBridge = loadLayoutBridge(); - progress.worked(10); - - // and finally create the PlatformData with all that we loaded. - targetData.setExtraData(frameworkRepository, - manifestDescriptors, - layoutDescriptors, - menuDescriptors, - xmlDescriptors, - enumValueMap, - permissionValues, - activity_actions.toArray(new String[activity_actions.size()]), - broadcast_actions.toArray(new String[broadcast_actions.size()]), - service_actions.toArray(new String[service_actions.size()]), - categories.toArray(new String[categories.size()]), - resources, - layoutBridge); - - Sdk.getCurrent().setTargetData(mAndroidTarget, targetData); - - return Status.OK_STATUS; - } catch (Exception e) { - AdtPlugin.logAndPrintError(e, TAG, "SDK parser failed"); //$NON-NLS-1$ - AdtPlugin.printToConsole("SDK parser failed", e.getMessage()); - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "SDK parser failed", e); - } finally { - if (monitor != null) { - monitor.done(); - } - } - } - - /** - * Preloads all "interesting" classes from the framework SDK jar. - * <p/> - * Currently this preloads all classes from the framework jar - * - * @param classLoader The framework SDK jar classloader - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - private void preload(AndroidJarLoader classLoader, IProgressMonitor monitor) { - try { - classLoader.preLoadClasses("" /* all classes */, //$NON-NLS-1$ - mAndroidTarget.getName(), // monitor task label - monitor); - } catch (InvalidAttributeValueException e) { - AdtPlugin.log(e, "Problem preloading classes"); //$NON-NLS-1$ - } catch (IOException e) { - AdtPlugin.log(e, "Problem preloading classes"); //$NON-NLS-1$ - } - } - - /** - * Creates an IResourceRepository for the framework resources. - * - * @param classLoader The framework SDK jar classloader - * @return a map of the resources, or null if it failed. - */ - private IResourceRepository collectResourceIds( - AndroidJarLoader classLoader) { - try { - Class<?> r = classLoader.loadClass(AndroidConstants.CLASS_R); - - if (r != null) { - Map<ResourceType, List<ResourceItem>> map = parseRClass(r); - if (map != null) { - return new FrameworkResourceRepository(map); - } - } - } catch (ClassNotFoundException e) { - AdtPlugin.logAndPrintError(e, TAG, - "Collect resource IDs failed, class %1$s not found in %2$s", //$NON-NLS-1$ - AndroidConstants.CLASS_R, - mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR)); - } - - return null; - } - - /** - * Parse the R class and build the resource map. - * - * @param rClass the Class object representing the Resources. - * @return a map of the resource or null - */ - private Map<ResourceType, List<ResourceItem>> parseRClass(Class<?> rClass) { - // get the sub classes. - Class<?>[] classes = rClass.getClasses(); - - if (classes.length > 0) { - HashMap<ResourceType, List<ResourceItem>> map = - new HashMap<ResourceType, List<ResourceItem>>(); - - // get the fields of each class. - for (int c = 0 ; c < classes.length ; c++) { - Class<?> subClass = classes[c]; - String name = subClass.getSimpleName(); - - // get the matching ResourceType - ResourceType type = ResourceType.getEnum(name); - if (type != null) { - List<ResourceItem> list = new ArrayList<ResourceItem>(); - map.put(type, list); - - Field[] fields = subClass.getFields(); - - for (Field f : fields) { - list.add(new ResourceItem(f.getName())); - } - } - } - - return map; - } - - return null; - } - - /** - * Loads, collects and returns the list of default permissions from the framework. - * - * @param classLoader The framework SDK jar classloader - * @return a non null (but possibly empty) array containing the permission values. - */ - private String[] collectPermissions(AndroidJarLoader classLoader) { - try { - Class<?> permissionClass = - classLoader.loadClass(AndroidConstants.CLASS_MANIFEST_PERMISSION); - - if (permissionClass != null) { - ArrayList<String> list = new ArrayList<String>(); - - Field[] fields = permissionClass.getFields(); - - for (Field f : fields) { - int modifiers = f.getModifiers(); - if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers) && - Modifier.isPublic(modifiers)) { - try { - Object value = f.get(null); - if (value instanceof String) { - list.add((String)value); - } - } catch (IllegalArgumentException e) { - // since we provide null this should not happen - } catch (IllegalAccessException e) { - // if the field is inaccessible we ignore it. - } catch (NullPointerException npe) { - // looks like this is not a static field. we can ignore. - } catch (ExceptionInInitializerError eiie) { - // lets just ignore the field again - } - } - } - - return list.toArray(new String[list.size()]); - } - } catch (ClassNotFoundException e) { - AdtPlugin.logAndPrintError(e, TAG, - "Collect permissions failed, class %1$s not found in %2$s", //$NON-NLS-1$ - AndroidConstants.CLASS_MANIFEST_PERMISSION, - mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR)); - } - - return new String[0]; - } - - /** - * Loads and collects the action and category default values from the framework. - * The values are added to the <code>actions</code> and <code>categories</code> lists. - * - * @param activityActions the list which will receive the activity action values. - * @param broadcastActions the list which will receive the broadcast action values. - * @param serviceActions the list which will receive the service action values. - * @param categories the list which will receive the category values. - */ - private void collectIntentFilterActionsAndCategories(ArrayList<String> activityActions, - ArrayList<String> broadcastActions, - ArrayList<String> serviceActions, ArrayList<String> categories) { - collectValues(mAndroidTarget.getPath(IAndroidTarget.ACTIONS_ACTIVITY), - activityActions); - collectValues(mAndroidTarget.getPath(IAndroidTarget.ACTIONS_BROADCAST), - broadcastActions); - collectValues(mAndroidTarget.getPath(IAndroidTarget.ACTIONS_SERVICE), - serviceActions); - collectValues(mAndroidTarget.getPath(IAndroidTarget.CATEGORIES), - categories); - } - - /** - * Collects values from a text file located in the SDK - * @param osFilePath The path to the text file. - * @param values the {@link ArrayList} to fill with the values. - */ - private void collectValues(String osFilePath, ArrayList<String> values) { - FileReader fr = null; - BufferedReader reader = null; - try { - fr = new FileReader(osFilePath); - reader = new BufferedReader(fr); - - String line; - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.length() > 0 && line.startsWith("#") == false) { //$NON-NLS-1$ - values.add(line); - } - } - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read SDK values"); //$NON-NLS-1$ - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read SDK values"); //$NON-NLS-1$ - } - - try { - if (fr != null) { - fr.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read SDK values"); //$NON-NLS-1$ - } - } - } - - /** - * Collects all layout classes information from the class loader and the - * attrs.xml and sets the corresponding structures in the resource manager. - * - * @param classLoader The framework SDK jar classloader in case we cannot get the widget from - * the platform directly - * @param attrsXmlParser The parser of the attrs.xml file - * @param mainList the Collection to receive the main list of {@link ViewClassInfo}. - * @param groupList the Collection to receive the group list of {@link ViewClassInfo}. - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - private void collectLayoutClasses(AndroidJarLoader classLoader, - AttrsXmlParser attrsXmlParser, - Collection<ViewClassInfo> mainList, Collection<ViewClassInfo> groupList, - IProgressMonitor monitor) { - LayoutParamsParser ldp = null; - try { - WidgetClassLoader loader = new WidgetClassLoader( - mAndroidTarget.getPath(IAndroidTarget.WIDGETS)); - if (loader.parseWidgetList(monitor)) { - ldp = new LayoutParamsParser(loader, attrsXmlParser); - } - // if the parsing failed, we'll use the old loader below. - } catch (FileNotFoundException e) { - AdtPlugin.log(e, "Android Framework Parser"); //$NON-NLS-1$ - // the file does not exist, we'll use the old loader below. - } - - if (ldp == null) { - ldp = new LayoutParamsParser(classLoader, attrsXmlParser); - } - ldp.parseLayoutClasses(monitor); - - List<ViewClassInfo> views = ldp.getViews(); - List<ViewClassInfo> groups = ldp.getGroups(); - - if (views != null && groups != null) { - mainList.addAll(views); - groupList.addAll(groups); - } - } - - /** - * Collects all preferences definition information from the attrs.xml and - * sets the corresponding structures in the resource manager. - * - * @param classLoader The framework SDK jar classloader - * @param attrsXmlParser The parser of the attrs.xml file - * @param mainList the Collection to receive the main list of {@link ViewClassInfo}. - * @param groupList the Collection to receive the group list of {@link ViewClassInfo}. - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - private void collectPreferenceClasses(AndroidJarLoader classLoader, - AttrsXmlParser attrsXmlParser, Collection<ViewClassInfo> mainList, - Collection<ViewClassInfo> groupList, IProgressMonitor monitor) { - LayoutParamsParser ldp = new LayoutParamsParser(classLoader, attrsXmlParser); - - try { - ldp.parsePreferencesClasses(monitor); - - List<ViewClassInfo> prefs = ldp.getViews(); - List<ViewClassInfo> groups = ldp.getGroups(); - - if (prefs != null && groups != null) { - mainList.addAll(prefs); - groupList.addAll(groups); - } - } catch (NoClassDefFoundError e) { - AdtPlugin.logAndPrintError(e, TAG, - "Collect preferences failed, class %1$s not found in %2$s", - e.getMessage(), - classLoader.getSource()); - } catch (Throwable e) { - AdtPlugin.log(e, "Android Framework Parser: failed to collect preference classes"); //$NON-NLS-1$ - AdtPlugin.printErrorToConsole("Android Framework Parser", - "failed to collect preference classes"); - } - } - - /** - * Collects all menu definition information from the attrs.xml and returns it. - * - * @param attrsXmlParser The parser of the attrs.xml file - */ - private Map<String, DeclareStyleableInfo> collectMenuDefinitions( - AttrsXmlParser attrsXmlParser) { - Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); - Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>(); - for (String key : new String[] { "Menu", //$NON-NLS-1$ - "MenuItem", //$NON-NLS-1$ - "MenuGroup" }) { //$NON-NLS-1$ - if (map.containsKey(key)) { - map2.put(key, map.get(key)); - } else { - AdtPlugin.log(IStatus.WARNING, - "Menu declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath()); - AdtPlugin.printErrorToConsole("Android Framework Parser", - String.format("Menu declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath())); - } - } - - return Collections.unmodifiableMap(map2); - } - - /** - * Collects all searchable definition information from the attrs.xml and returns it. - * - * @param attrsXmlParser The parser of the attrs.xml file - */ - private Map<String, DeclareStyleableInfo> collectSearchableDefinitions( - AttrsXmlParser attrsXmlParser) { - Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList(); - Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>(); - for (String key : new String[] { "Searchable", //$NON-NLS-1$ - "SearchableActionKey" }) { //$NON-NLS-1$ - if (map.containsKey(key)) { - map2.put(key, map.get(key)); - } else { - AdtPlugin.log(IStatus.WARNING, - "Searchable declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath()); - AdtPlugin.printErrorToConsole("Android Framework Parser", - String.format("Searchable declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$ - key, attrsXmlParser.getOsAttrsXmlPath())); - } - } - - return Collections.unmodifiableMap(map2); - } - - /** - * Collects all manifest definition information from the attrs_manifest.xml and returns it. - */ - private Map<String, DeclareStyleableInfo> collectManifestDefinitions( - AttrsXmlParser attrsXmlParser) { - - return attrsXmlParser.getDeclareStyleableList(); - } - - /** - * Loads the layout bridge from the dynamically loaded layoutlib.jar - */ - private LayoutBridge loadLayoutBridge() { - LayoutBridge layoutBridge = new LayoutBridge(); - - try { - // get the URL for the file. - File f = new File(mAndroidTarget.getPath(IAndroidTarget.LAYOUT_LIB)); - if (f.isFile() == false) { - AdtPlugin.log(IStatus.ERROR, "layoutlib.jar is missing!"); //$NON-NLS-1$ - } else { - URL url = f.toURL(); - - // create a class loader. Because this jar reference interfaces - // that are in the editors plugin, it's important to provide - // a parent class loader. - layoutBridge.classLoader = new URLClassLoader(new URL[] { url }, - this.getClass().getClassLoader()); - - // load the class - Class<?> clazz = layoutBridge.classLoader.loadClass(AndroidConstants.CLASS_BRIDGE); - if (clazz != null) { - // instantiate an object of the class. - Constructor<?> constructor = clazz.getConstructor(); - if (constructor != null) { - Object bridge = constructor.newInstance(); - if (bridge instanceof ILayoutBridge) { - layoutBridge.bridge = (ILayoutBridge)bridge; - } - } - } - - if (layoutBridge.bridge == null) { - layoutBridge.status = LoadStatus.FAILED; - AdtPlugin.log(IStatus.ERROR, "Failed to load " + AndroidConstants.CLASS_BRIDGE); //$NON-NLS-1$ - } else { - layoutBridge.status = LoadStatus.LOADED; - } - } - } catch (Throwable t) { - layoutBridge.status = LoadStatus.FAILED; - // log the error. - AdtPlugin.log(t, "Failed to load the LayoutLib"); - } - - return layoutBridge; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/FrameworkResourceRepository.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/FrameworkResourceRepository.java deleted file mode 100644 index f4b10df..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/FrameworkResourceRepository.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Implementation of the {@link IResourceRepository} interface to hold the system resource Ids - * parsed by {@link AndroidTargetParser}. - */ -final class FrameworkResourceRepository implements IResourceRepository { - - private Map<ResourceType, List<ResourceItem>> mResourcesMap; - - public FrameworkResourceRepository(Map<ResourceType, List<ResourceItem>> systemResourcesMap) { - mResourcesMap = systemResourcesMap; - } - - public ResourceType[] getAvailableResourceTypes() { - if (mResourcesMap != null) { - Set<ResourceType> types = mResourcesMap.keySet(); - - if (types != null) { - return types.toArray(new ResourceType[types.size()]); - } - } - - return null; - } - - public ResourceItem[] getResources(ResourceType type) { - if (mResourcesMap != null) { - List<ResourceItem> items = mResourcesMap.get(type); - - if (items != null) { - return items.toArray(new ResourceItem[items.size()]); - } - } - - return null; - } - - public boolean hasResources(ResourceType type) { - if (mResourcesMap != null) { - List<ResourceItem> items = mResourcesMap.get(type); - - return (items != null && items.size() > 0); - } - - return false; - } - - public boolean isSystemRepository() { - return true; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java deleted file mode 100644 index 35057d1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; - -import javax.management.InvalidAttributeValueException; - -/** - * Classes which implements this interface provide methods to access framework resource - * data loaded from the SDK. - */ -public interface IAndroidClassLoader { - - /** - * Classes which implement this interface provide methods to describe a class. - */ - public interface IClassDescriptor { - - String getCanonicalName(); - - IClassDescriptor getSuperclass(); - - String getSimpleName(); - - IClassDescriptor getEnclosingClass(); - - IClassDescriptor[] getDeclaredClasses(); - - boolean isInstantiable(); - } - - /** - * Finds and loads all classes that derive from a given set of super classes. - * - * @param rootPackage Root package of classes to find. Use an empty string to find everyting. - * @param superClasses The super classes of all the classes to find. - * @return An hash map which keys are the super classes looked for and which values are - * ArrayList of the classes found. The array lists are always created for all the - * valid keys, they are simply empty if no deriving class is found for a given - * super class. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - public HashMap<String, ArrayList<IClassDescriptor>> findClassesDerivingFrom( - String rootPackage, String[] superClasses) - throws IOException, InvalidAttributeValueException, ClassFormatError; - - /** - * Returns a {@link IClassDescriptor} by its fully-qualified name. - * @param className the fully-qualified name of the class to return. - * @throws ClassNotFoundException - */ - public IClassDescriptor getClass(String className) throws ClassNotFoundException; - - /** - * Returns a string indicating the source of the classes, typically for debugging - * or in error messages. This would typically be a JAR file name or some kind of - * identifier that would mean something to the user when looking at error messages. - * - * @return An informal string representing the source of the classes. - */ - public String getSource(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/LayoutParamsParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/LayoutParamsParser.java deleted file mode 100644 index dc600d7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/LayoutParamsParser.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.IAndroidClassLoader.IClassDescriptor; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.AttrsXmlParser; -import com.android.ide.eclipse.common.resources.ViewClassInfo; -import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.SubMonitor; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; - -import javax.management.InvalidAttributeValueException; - -/* - * TODO: refactor this. Could use some cleanup. - */ - -/** - * Parser for the framework library. - * <p/> - * This gather the following information: - * <ul> - * <li>Resource ID from <code>android.R</code></li> - * <li>The list of permissions values from <code>android.Manifest$permission</code></li> - * <li></li> - * </ul> - */ -public class LayoutParamsParser { - - /** - * Class extending {@link ViewClassInfo} by adding the notion of instantiability. - * {@link LayoutParamsParser#getViews()} and {@link LayoutParamsParser#getGroups()} should - * only return classes that can be instantiated. - */ - final static class ExtViewClassInfo extends ViewClassInfo { - - private boolean mIsInstantiable; - - ExtViewClassInfo(boolean instantiable, boolean isLayout, String canonicalClassName, - String shortClassName) { - super(isLayout, canonicalClassName, shortClassName); - mIsInstantiable = instantiable; - } - - boolean isInstantiable() { - return mIsInstantiable; - } - } - - /* Note: protected members/methods are overridden in unit tests */ - - /** Reference to android.view.View */ - protected IClassDescriptor mTopViewClass; - /** Reference to android.view.ViewGroup */ - protected IClassDescriptor mTopGroupClass; - /** Reference to android.view.ViewGroup$LayoutParams */ - protected IClassDescriptor mTopLayoutParamsClass; - - /** Input list of all classes deriving from android.view.View */ - protected ArrayList<IClassDescriptor> mViewList; - /** Input list of all classes deriving from android.view.ViewGroup */ - protected ArrayList<IClassDescriptor> mGroupList; - - /** Output map of FQCN => info on View classes */ - protected TreeMap<String, ExtViewClassInfo> mViewMap; - /** Output map of FQCN => info on ViewGroup classes */ - protected TreeMap<String, ExtViewClassInfo> mGroupMap; - /** Output map of FQCN => info on LayoutParams classes */ - protected HashMap<String, LayoutParamsInfo> mLayoutParamsMap; - - /** The attrs.xml parser */ - protected AttrsXmlParser mAttrsXmlParser; - - /** The android.jar class loader */ - protected IAndroidClassLoader mClassLoader; - - /** - * Instantiate a new LayoutParamsParser. - * @param classLoader The android.jar class loader - * @param attrsXmlParser The parser of the attrs.xml file - */ - public LayoutParamsParser(IAndroidClassLoader classLoader, - AttrsXmlParser attrsXmlParser) { - mClassLoader = classLoader; - mAttrsXmlParser = attrsXmlParser; - } - - /** Returns the map of FQCN => info on View classes */ - public List<ViewClassInfo> getViews() { - return getInstantiables(mViewMap); - } - - /** Returns the map of FQCN => info on ViewGroup classes */ - public List<ViewClassInfo> getGroups() { - return getInstantiables(mGroupMap); - } - - /** - * TODO: doc here. - * <p/> - * Note: on output we should have NO dependency on {@link IClassDescriptor}, - * otherwise we wouldn't be able to unload the class loader later. - * <p/> - * Note on Vocabulary: FQCN=Fully Qualified Class Name (e.g. "my.package.class$innerClass") - * @param monitor A progress monitor. Can be null. Caller is responsible for calling done. - */ - public void parseLayoutClasses(IProgressMonitor monitor) { - parseClasses(monitor, - AndroidConstants.CLASS_VIEW, - AndroidConstants.CLASS_VIEWGROUP, - AndroidConstants.CLASS_VIEWGROUP_LAYOUTPARAMS); - } - - public void parsePreferencesClasses(IProgressMonitor monitor) { - parseClasses(monitor, - AndroidConstants.CLASS_PREFERENCE, - AndroidConstants.CLASS_PREFERENCEGROUP, - null /* paramsClassName */ ); - } - - private void parseClasses(IProgressMonitor monitor, - String rootClassName, - String groupClassName, - String paramsClassName) { - try { - SubMonitor progress = SubMonitor.convert(monitor, 100); - - String[] superClasses = new String[2 + (paramsClassName == null ? 0 : 1)]; - superClasses[0] = groupClassName; - superClasses[1] = rootClassName; - if (paramsClassName != null) { - superClasses[2] = paramsClassName; - } - HashMap<String, ArrayList<IClassDescriptor>> found = - mClassLoader.findClassesDerivingFrom("android.", superClasses); - mTopViewClass = mClassLoader.getClass(rootClassName); - mTopGroupClass = mClassLoader.getClass(groupClassName); - if (paramsClassName != null) { - mTopLayoutParamsClass = mClassLoader.getClass(paramsClassName); - } - - mViewList = found.get(rootClassName); - mGroupList = found.get(groupClassName); - - mViewMap = new TreeMap<String, ExtViewClassInfo>(); - mGroupMap = new TreeMap<String, ExtViewClassInfo>(); - if (mTopLayoutParamsClass != null) { - mLayoutParamsMap = new HashMap<String, LayoutParamsInfo>(); - } - - // Add top classes to the maps since by design they are not listed in classes deriving - // from themselves. - addGroup(mTopGroupClass); - addView(mTopViewClass); - - // ViewGroup derives from View - mGroupMap.get(groupClassName).setSuperClass( - mViewMap.get(rootClassName)); - - progress.setWorkRemaining(mGroupList.size() + mViewList.size()); - - for (IClassDescriptor groupChild : mGroupList) { - addGroup(groupChild); - progress.worked(1); - } - - for (IClassDescriptor viewChild : mViewList) { - if (viewChild != mTopGroupClass) { - addView(viewChild); - } - progress.worked(1); - } - } catch (ClassNotFoundException e) { - AdtPlugin.log(e, "Problem loading class %1$s or %2$s", //$NON-NLS-1$ - rootClassName, groupClassName); - } catch (InvalidAttributeValueException e) { - AdtPlugin.log(e, "Problem loading classes"); //$NON-NLS-1$ - } catch (ClassFormatError e) { - AdtPlugin.log(e, "Problem loading classes"); //$NON-NLS-1$ - } catch (IOException e) { - AdtPlugin.log(e, "Problem loading classes"); //$NON-NLS-1$ - } - } - - /** - * Parses a View class and adds a ExtViewClassInfo for it in mViewMap. - * It calls itself recursively to handle super classes which are also Views. - */ - private ExtViewClassInfo addView(IClassDescriptor viewClass) { - String fqcn = viewClass.getCanonicalName(); - if (mViewMap.containsKey(fqcn)) { - return mViewMap.get(fqcn); - } else if (mGroupMap.containsKey(fqcn)) { - return mGroupMap.get(fqcn); - } - - ExtViewClassInfo info = new ExtViewClassInfo(viewClass.isInstantiable(), - false /* layout */, fqcn, viewClass.getSimpleName()); - mViewMap.put(fqcn, info); - - // All view classes derive from mTopViewClass by design. - // Do not lookup the super class for mTopViewClass itself. - if (viewClass.equals(mTopViewClass) == false) { - IClassDescriptor superClass = viewClass.getSuperclass(); - ExtViewClassInfo superClassInfo = addView(superClass); - info.setSuperClass(superClassInfo); - } - - mAttrsXmlParser.loadViewAttributes(info); - return info; - } - - /** - * Parses a ViewGroup class and adds a ExtViewClassInfo for it in mGroupMap. - * It calls itself recursively to handle super classes which are also ViewGroups. - */ - private ExtViewClassInfo addGroup(IClassDescriptor groupClass) { - String fqcn = groupClass.getCanonicalName(); - if (mGroupMap.containsKey(fqcn)) { - return mGroupMap.get(fqcn); - } - - ExtViewClassInfo info = new ExtViewClassInfo(groupClass.isInstantiable(), - true /* layout */, fqcn, groupClass.getSimpleName()); - mGroupMap.put(fqcn, info); - - // All groups derive from android.view.ViewGroup, which in turns derives from - // android.view.View (i.e. mTopViewClass here). So the only group that can have View as - // its super class is the ViewGroup base class and we don't try to resolve it since groups - // are loaded before views. - IClassDescriptor superClass = groupClass.getSuperclass(); - - // Assertion: at this point, we should have - // superClass != mTopViewClass || fqcn.equals(AndroidConstants.CLASS_VIEWGROUP); - - if (superClass != null && superClass.equals(mTopViewClass) == false) { - ExtViewClassInfo superClassInfo = addGroup(superClass); - - // Assertion: we should have superClassInfo != null && superClassInfo != info; - if (superClassInfo != null && superClassInfo != info) { - info.setSuperClass(superClassInfo); - } - } - - mAttrsXmlParser.loadViewAttributes(info); - if (mTopLayoutParamsClass != null) { - info.setLayoutParams(addLayoutParams(groupClass)); - } - return info; - } - - /** - * Parses a ViewGroup class and returns an info object on its inner LayoutParams. - * - * @return The {@link LayoutParamsInfo} for the ViewGroup class or null. - */ - private LayoutParamsInfo addLayoutParams(IClassDescriptor groupClass) { - - // Is there a LayoutParams in this group class? - IClassDescriptor layoutParamsClass = findLayoutParams(groupClass); - - // if there's no layout data in the group class, link to the one from the - // super class. - if (layoutParamsClass == null) { - for (IClassDescriptor superClass = groupClass.getSuperclass(); - layoutParamsClass == null && - superClass != null && - superClass.equals(mTopViewClass) == false; - superClass = superClass.getSuperclass()) { - layoutParamsClass = findLayoutParams(superClass); - } - } - - if (layoutParamsClass != null) { - return getLayoutParamsInfo(layoutParamsClass); - } - - return null; - } - - /** - * Parses a LayoutParams class and returns a LayoutParamsInfo object for it. - * It calls itself recursively to handle the super class of the LayoutParams. - */ - private LayoutParamsInfo getLayoutParamsInfo(IClassDescriptor layoutParamsClass) { - String fqcn = layoutParamsClass.getCanonicalName(); - LayoutParamsInfo layoutParamsInfo = mLayoutParamsMap.get(fqcn); - - if (layoutParamsInfo != null) { - return layoutParamsInfo; - } - - // Find the link on the LayoutParams super class - LayoutParamsInfo superClassInfo = null; - if (layoutParamsClass.equals(mTopLayoutParamsClass) == false) { - IClassDescriptor superClass = layoutParamsClass.getSuperclass(); - superClassInfo = getLayoutParamsInfo(superClass); - } - - // Find the link on the enclosing ViewGroup - ExtViewClassInfo enclosingGroupInfo = addGroup(layoutParamsClass.getEnclosingClass()); - - layoutParamsInfo = new ExtViewClassInfo.LayoutParamsInfo( - enclosingGroupInfo, layoutParamsClass.getSimpleName(), superClassInfo); - mLayoutParamsMap.put(fqcn, layoutParamsInfo); - - mAttrsXmlParser.loadLayoutParamsAttributes(layoutParamsInfo); - - return layoutParamsInfo; - } - - /** - * Given a ViewGroup-derived class, looks for an inner class named LayoutParams - * and if found returns its class definition. - * <p/> - * This uses the actual defined inner classes and does not look at inherited classes. - * - * @param groupClass The ViewGroup derived class - * @return The Class of the inner LayoutParams or null if none is declared. - */ - private IClassDescriptor findLayoutParams(IClassDescriptor groupClass) { - IClassDescriptor[] innerClasses = groupClass.getDeclaredClasses(); - for (IClassDescriptor innerClass : innerClasses) { - if (innerClass.getSimpleName().equals(AndroidConstants.CLASS_LAYOUTPARAMS)) { - return innerClass; - } - } - return null; - } - - /** - * Computes and return a list of ViewClassInfo from a map by filtering out the class that - * cannot be instantiated. - */ - private List<ViewClassInfo> getInstantiables(SortedMap<String, ExtViewClassInfo> map) { - Collection<ExtViewClassInfo> values = map.values(); - ArrayList<ViewClassInfo> list = new ArrayList<ViewClassInfo>(); - - for (ExtViewClassInfo info : values) { - if (info.isInstantiable()) { - list.add(info); - } - } - - return list; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/LoadStatus.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/LoadStatus.java deleted file mode 100644 index 6bf0272..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/LoadStatus.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -/** - * Enum for loading status of various SDK parts. - */ -public enum LoadStatus { - LOADING, LOADED, FAILED; -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java deleted file mode 100644 index c7773cc..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener; -import com.android.prefs.AndroidLocation.AndroidLocationException; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.ISdkLog; -import com.android.sdklib.SdkConstants; -import com.android.sdklib.SdkManager; -import com.android.sdklib.avd.AvdManager; -import com.android.sdklib.project.ApkConfigurationHelper; -import com.android.sdklib.project.ProjectProperties; -import com.android.sdklib.project.ProjectProperties.PropertyType; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -/** - * Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used - * at the same time. - * - * To start using an SDK, call {@link #loadSdk(String)} which returns the instance of - * the Sdk object. - * - * To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}. - */ -public class Sdk implements IProjectListener { - private static Sdk sCurrentSdk = null; - - private final SdkManager mManager; - private final AvdManager mAvdManager; - - private final HashMap<IProject, IAndroidTarget> mProjectTargetMap = - new HashMap<IProject, IAndroidTarget>(); - private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap = - new HashMap<IAndroidTarget, AndroidTargetData>(); - private final HashMap<IProject, Map<String, String>> mProjectApkConfigMap = - new HashMap<IProject, Map<String, String>>(); - private final String mDocBaseUrl; - - /** - * Loads an SDK and returns an {@link Sdk} object if success. - * @param sdkLocation the OS path to the SDK. - */ - public static Sdk loadSdk(String sdkLocation) { - if (sCurrentSdk != null) { - sCurrentSdk.dispose(); - sCurrentSdk = null; - } - - final ArrayList<String> logMessages = new ArrayList<String>(); - ISdkLog log = new ISdkLog() { - public void error(Throwable throwable, String errorFormat, Object... arg) { - if (errorFormat != null) { - logMessages.add(String.format(errorFormat, arg)); - } - - if (throwable != null) { - logMessages.add(throwable.getMessage()); - } - } - - public void warning(String warningFormat, Object... arg) { - logMessages.add(String.format(warningFormat, arg)); - } - - public void printf(String msgFormat, Object... arg) { - logMessages.add(String.format(msgFormat, arg)); - } - }; - - // get an SdkManager object for the location - SdkManager manager = SdkManager.createManager(sdkLocation, log); - if (manager != null) { - AvdManager avdManager = null; - try { - avdManager = new AvdManager(manager, log); - } catch (AndroidLocationException e) { - log.error(e, "Error parsing the AVDs"); - } - sCurrentSdk = new Sdk(manager, avdManager); - return sCurrentSdk; - } else { - StringBuilder sb = new StringBuilder("Error Loading the SDK:\n"); - for (String msg : logMessages) { - sb.append('\n'); - sb.append(msg); - } - AdtPlugin.displayError("Android SDK", sb.toString()); - } - return null; - } - - /** - * Returns the current {@link Sdk} object. - */ - public static Sdk getCurrent() { - return sCurrentSdk; - } - - /** - * Returns the location (OS path) of the current SDK. - */ - public String getSdkLocation() { - return mManager.getLocation(); - } - - /** - * Returns the URL to the local documentation. - * Can return null if no documentation is found in the current SDK. - * - * @return A file:// URL on the local documentation folder if it exists or null. - */ - public String getDocumentationBaseUrl() { - return mDocBaseUrl; - } - - /** - * Returns the list of targets that are available in the SDK. - */ - public IAndroidTarget[] getTargets() { - return mManager.getTargets(); - } - - /** - * Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}. - * - * @param hash the {@link IAndroidTarget} hash string. - * @return The matching {@link IAndroidTarget} or null. - */ - public IAndroidTarget getTargetFromHashString(String hash) { - return mManager.getTargetFromHashString(hash); - } - - /** - * Associates an {@link IProject} and an {@link IAndroidTarget}. - */ - public void setProject(IProject project, IAndroidTarget target) { - synchronized (mProjectTargetMap) { - // look for the current target of the project - IAndroidTarget previousTarget = mProjectTargetMap.get(project); - - if (target != previousTarget) { - // save the target hash string in the project persistent property - setProjectTargetHashString(project, target.hashString()); - - // put it in a local map for easy access. - mProjectTargetMap.put(project, target); - - // recompile the project if needed. - IJavaProject javaProject = JavaCore.create(project); - AndroidClasspathContainerInitializer.updateProjects( - new IJavaProject[] { javaProject }); - } - } - } - - /** - * Returns the {@link IAndroidTarget} object associated with the given {@link IProject}. - */ - public IAndroidTarget getTarget(IProject project) { - synchronized (mProjectTargetMap) { - IAndroidTarget target = mProjectTargetMap.get(project); - if (target == null) { - // get the value from the project persistent property. - String targetHashString = loadProjectProperties(project, this); - - if (targetHashString != null) { - target = mManager.getTargetFromHashString(targetHashString); - } - } - - return target; - } - } - - - /** - * Parses the project properties and returns the hash string uniquely identifying the - * target of the given project. - * <p/> - * This methods reads the content of the <code>default.properties</code> file present in - * the root folder of the project. - * <p/>The returned string is equivalent to the return of {@link IAndroidTarget#hashString()}. - * @param project The project for which to return the target hash string. - * @param sdkStorage The sdk in which to store the Apk Configs. Can be null. - * @return the hash string or null if the project does not have a target set. - */ - private static String loadProjectProperties(IProject project, Sdk sdkStorage) { - // load the default.properties from the project folder. - ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(), - PropertyType.DEFAULT); - if (properties == null) { - AdtPlugin.log(IStatus.ERROR, "Failed to load properties file for project '%s'", - project.getName()); - return null; - } - - if (sdkStorage != null) { - Map<String, String> configMap = ApkConfigurationHelper.getConfigs(properties); - - if (configMap.size() > 0) { - sdkStorage.mProjectApkConfigMap.put(project, configMap); - } - } - - return properties.getProperty(ProjectProperties.PROPERTY_TARGET); - } - - /** - * Returns the hash string uniquely identifying the target of a project. - * <p/> - * This methods reads the content of the <code>default.properties</code> file present in - * the root folder of the project. - * <p/>The string is equivalent to the return of {@link IAndroidTarget#hashString()}. - * @param project The project for which to return the target hash string. - * @return the hash string or null if the project does not have a target set. - */ - public static String getProjectTargetHashString(IProject project) { - return loadProjectProperties(project, null /*storeConfigs*/); - } - - /** - * Sets a target hash string in given project's <code>default.properties</code> file. - * @param project The project in which to save the hash string. - * @param targetHashString The target hash string to save. This must be the result from - * {@link IAndroidTarget#hashString()}. - */ - public static void setProjectTargetHashString(IProject project, String targetHashString) { - // because we don't want to erase other properties from default.properties, we first load - // them - ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(), - PropertyType.DEFAULT); - if (properties == null) { - // doesn't exist yet? we create it. - properties = ProjectProperties.create(project.getLocation().toOSString(), - PropertyType.DEFAULT); - } - - // add/change the target hash string. - properties.setProperty(ProjectProperties.PROPERTY_TARGET, targetHashString); - - // and rewrite the file. - try { - properties.save(); - } catch (IOException e) { - AdtPlugin.log(e, "Failed to save default.properties for project '%s'", - project.getName()); - } - } - /** - * Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}. - */ - public AndroidTargetData getTargetData(IAndroidTarget target) { - synchronized (mTargetDataMap) { - return mTargetDataMap.get(target); - } - } - - /** - * Returns the configuration map for a given project. - * <p/>The Map key are name to be used in the apk filename, while the values are comma separated - * config values. The config value can be passed directly to aapt through the -c option. - */ - public Map<String, String> getProjectApkConfigs(IProject project) { - return mProjectApkConfigMap.get(project); - } - - public void setProjectApkConfigs(IProject project, Map<String, String> configMap) - throws CoreException { - // first set the new map - mProjectApkConfigMap.put(project, configMap); - - // Now we write this in default.properties. - // Because we don't want to erase other properties from default.properties, we first load - // them - ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(), - PropertyType.DEFAULT); - if (properties == null) { - // doesn't exist yet? we create it. - properties = ProjectProperties.create(project.getLocation().toOSString(), - PropertyType.DEFAULT); - } - - // sets the configs in the property file. - boolean hasRemovedConfig = ApkConfigurationHelper.setConfigs(properties, configMap); - - // and rewrite the file. - try { - properties.save(); - } catch (IOException e) { - AdtPlugin.log(e, "Failed to save default.properties for project '%s'", - project.getName()); - } - - // we're done, force a rebuild. If there was removed config, we clean instead of build - // (to remove the obsolete ap_ and apk file from removed configs). - project.build(hasRemovedConfig ? - IncrementalProjectBuilder.CLEAN_BUILD : IncrementalProjectBuilder.FULL_BUILD, - null); - } - - /** - * Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could - * be <code>null</code>. - */ - public AvdManager getAvdManager() { - return mAvdManager; - } - - private Sdk(SdkManager manager, AvdManager avdManager) { - mManager = manager; - mAvdManager = avdManager; - - // listen to projects closing - ResourceMonitor monitor = ResourceMonitor.getMonitor(); - monitor.addProjectListener(this); - - // pre-compute some paths - mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() + - SdkConstants.OS_SDK_DOCS_FOLDER); - } - - /** - * Cleans and unloads the SDK. - */ - private void dispose() { - ResourceMonitor.getMonitor().removeProjectListener(this); - } - - void setTargetData(IAndroidTarget target, AndroidTargetData data) { - synchronized (mTargetDataMap) { - mTargetDataMap.put(target, data); - } - } - - /** - * Returns the URL to the local documentation. - * Can return null if no documentation is found in the current SDK. - * - * @param osDocsPath Path to the documentation folder in the current SDK. - * The folder may not actually exist. - * @return A file:// URL on the local documentation folder if it exists or null. - */ - private String getDocumentationBaseUrl(String osDocsPath) { - File f = new File(osDocsPath); - - if (f.isDirectory()) { - try { - // Note: to create a file:// URL, one would typically use something like - // f.toURI().toURL().toString(). However this generates a broken path on - // Windows, namely "C:\\foo" is converted to "file:/C:/foo" instead of - // "file:///C:/foo" (i.e. there should be 3 / after "file:"). So we'll - // do the correct thing manually. - - String path = f.getAbsolutePath(); - if (File.separatorChar != '/') { - path = path.replace(File.separatorChar, '/'); - } - - // For some reason the URL class doesn't add the mandatory "//" after - // the "file:" protocol name, so it has to be hacked into the path. - URL url = new URL("file", null, "//" + path); //$NON-NLS-1$ //$NON-NLS-2$ - String result = url.toString(); - return result; - } catch (MalformedURLException e) { - // ignore malformed URLs - } - } - - return null; - } - - public void projectClosed(IProject project) { - mProjectTargetMap.remove(project); - mProjectApkConfigMap.remove(project); - } - - public void projectDeleted(IProject project) { - projectClosed(project); - } - - public void projectOpened(IProject project) { - // ignore this. The project will be added to the map the first time the target needs - // to be resolved. - } - - public void projectOpenedWithWorkspace(IProject project) { - // ignore this. The project will be added to the map the first time the target needs - // to be resolved. - } -} - - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java deleted file mode 100644 index 0e60f8a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2008 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.sdk; - -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.runtime.IProgressMonitor; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.TreeMap; - -import javax.management.InvalidAttributeValueException; - -/** - * Parser for the text file containing the list of widgets, layouts and layout params. - * <p/> - * The file is a straight text file containing one class per line.<br> - * Each line is in the following format<br> - * <code>[code][class name] [super class name] [super class name]...</code> - * where code is a single letter (W for widget, L for layout, P for layout params), and class names - * are the fully qualified name of the classes. - */ -public final class WidgetClassLoader implements IAndroidClassLoader { - - /** - * Basic class containing the class descriptions found in the text file. - */ - private final static class ClassDescriptor implements IClassDescriptor { - - private String mName; - private String mSimpleName; - private ClassDescriptor mSuperClass; - private ClassDescriptor mEnclosingClass; - private final ArrayList<IClassDescriptor> mDeclaredClasses = - new ArrayList<IClassDescriptor>(); - private boolean mIsInstantiable = false; - - ClassDescriptor(String fqcn) { - mName = fqcn; - mSimpleName = getSimpleName(fqcn); - } - - public String getCanonicalName() { - return mName; - } - - public String getSimpleName() { - return mSimpleName; - } - - public IClassDescriptor[] getDeclaredClasses() { - return mDeclaredClasses.toArray(new IClassDescriptor[mDeclaredClasses.size()]); - } - - private void addDeclaredClass(ClassDescriptor declaredClass) { - mDeclaredClasses.add(declaredClass); - } - - public IClassDescriptor getEnclosingClass() { - return mEnclosingClass; - } - - void setEnclosingClass(ClassDescriptor enclosingClass) { - // set the enclosing class. - mEnclosingClass = enclosingClass; - - // add this to the list of declared class in the enclosing class. - mEnclosingClass.addDeclaredClass(this); - - // finally change the name of declared class to make sure it uses the - // convention: package.enclosing$declared instead of package.enclosing.declared - mName = enclosingClass.mName + "$" + mName.substring(enclosingClass.mName.length() + 1); - } - - public IClassDescriptor getSuperclass() { - return mSuperClass; - } - - void setSuperClass(ClassDescriptor superClass) { - mSuperClass = superClass; - } - - @Override - public boolean equals(Object clazz) { - if (clazz instanceof ClassDescriptor) { - return mName.equals(((ClassDescriptor)clazz).mName); - } - return super.equals(clazz); - } - - @Override - public int hashCode() { - return mName.hashCode(); - } - - public boolean isInstantiable() { - return mIsInstantiable; - } - - void setInstantiable(boolean state) { - mIsInstantiable = state; - } - - private String getSimpleName(String fqcn) { - String[] segments = fqcn.split("\\."); - return segments[segments.length-1]; - } - } - - private BufferedReader mReader; - - /** Output map of FQCN => descriptor on all classes */ - private final Map<String, ClassDescriptor> mMap = new TreeMap<String, ClassDescriptor>(); - /** Output map of FQCN => descriptor on View classes */ - private final Map<String, ClassDescriptor> mWidgetMap = new TreeMap<String, ClassDescriptor>(); - /** Output map of FQCN => descriptor on ViewGroup classes */ - private final Map<String, ClassDescriptor> mLayoutMap = new TreeMap<String, ClassDescriptor>(); - /** Output map of FQCN => descriptor on LayoutParams classes */ - private final Map<String, ClassDescriptor> mLayoutParamsMap = - new HashMap<String, ClassDescriptor>(); - /** File path of the source text file */ - private String mOsFilePath; - - /** - * Creates a loader with a given file path. - * @param osFilePath the OS path of the file to load. - * @throws FileNotFoundException if the file is not found. - */ - WidgetClassLoader(String osFilePath) throws FileNotFoundException { - mOsFilePath = osFilePath; - mReader = new BufferedReader(new FileReader(osFilePath)); - } - - public String getSource() { - return mOsFilePath; - } - - /** - * Parses the text file and return true if the file was successfully parsed. - * @param monitor - */ - boolean parseWidgetList(IProgressMonitor monitor) { - try { - String line; - while ((line = mReader.readLine()) != null) { - if (line.length() > 0) { - char prefix = line.charAt(0); - String[] classes = null; - ClassDescriptor clazz = null; - switch (prefix) { - case 'W': - classes = line.substring(1).split(" "); - clazz = processClass(classes, 0, null /* map */); - if (clazz != null) { - clazz.setInstantiable(true); - mWidgetMap.put(classes[0], clazz); - } - break; - case 'L': - classes = line.substring(1).split(" "); - clazz = processClass(classes, 0, null /* map */); - if (clazz != null) { - clazz.setInstantiable(true); - mLayoutMap.put(classes[0], clazz); - } - break; - case 'P': - classes = line.substring(1).split(" "); - clazz = processClass(classes, 0, mLayoutParamsMap); - if (clazz != null) { - clazz.setInstantiable(true); - } - break; - case '#': - // comment, do nothing - break; - default: - throw new IllegalArgumentException(); - } - } - } - - // reconciliate the layout and their layout params - postProcess(); - - return true; - } catch (IOException e) { - } finally { - try { - mReader.close(); - } catch (IOException e) { - } - } - - return false; - } - - /** - * Parses a View class and adds a ViewClassInfo for it in mWidgetMap. - * It calls itself recursively to handle super classes which are also Views. - * @param classes the inheritance list of the class to process. - * @param index the index of the class to process in the <code>classes</code> array. - * @param map an optional map in which to put every {@link ClassDescriptor} created. - */ - private ClassDescriptor processClass(String[] classes, int index, - Map<String, ClassDescriptor> map) { - if (index >= classes.length) { - return null; - } - - String fqcn = classes[index]; - - if ("java.lang.Object".equals(fqcn)) { //$NON-NLS-1$ - return null; - } - - // check if the ViewInfoClass has not yet been created. - if (mMap.containsKey(fqcn)) { - return mMap.get(fqcn); - } - - // create the custom class. - ClassDescriptor clazz = new ClassDescriptor(fqcn); - mMap.put(fqcn, clazz); - if (map != null) { - map.put(fqcn, clazz); - } - - // get the super class - ClassDescriptor superClass = processClass(classes, index+1, map); - if (superClass != null) { - clazz.setSuperClass(superClass); - } - - return clazz; - } - - /** - * Goes through the layout params and look for the enclosed class. If the layout params - * has no known enclosed type it is dropped. - */ - private void postProcess() { - Collection<ClassDescriptor> params = mLayoutParamsMap.values(); - - for (ClassDescriptor param : params) { - String fqcn = param.getCanonicalName(); - - // get the enclosed name. - String enclosed = getEnclosedName(fqcn); - - // look for a match in the layouts. We don't use the layout map as it only contains the - // end classes, but in this case we also need to process the layout params for the base - // layout classes. - ClassDescriptor enclosingType = mMap.get(enclosed); - if (enclosingType != null) { - param.setEnclosingClass(enclosingType); - - // remove the class from the map, and put it back with the fixed name - mMap.remove(fqcn); - mMap.put(param.getCanonicalName(), param); - } - } - } - - private String getEnclosedName(String fqcn) { - int index = fqcn.lastIndexOf('.'); - return fqcn.substring(0, index); - } - - /** - * Finds and loads all classes that derive from a given set of super classes. - * - * @param rootPackage Root package of classes to find. Use an empty string to find everyting. - * @param superClasses The super classes of all the classes to find. - * @return An hash map which keys are the super classes looked for and which values are - * ArrayList of the classes found. The array lists are always created for all the - * valid keys, they are simply empty if no deriving class is found for a given - * super class. - * @throws IOException - * @throws InvalidAttributeValueException - * @throws ClassFormatError - */ - public HashMap<String, ArrayList<IClassDescriptor>> findClassesDerivingFrom(String rootPackage, - String[] superClasses) throws IOException, InvalidAttributeValueException, - ClassFormatError { - HashMap<String, ArrayList<IClassDescriptor>> map = - new HashMap<String, ArrayList<IClassDescriptor>>(); - - ArrayList<IClassDescriptor> list = new ArrayList<IClassDescriptor>(); - list.addAll(mWidgetMap.values()); - map.put(AndroidConstants.CLASS_VIEW, list); - - list = new ArrayList<IClassDescriptor>(); - list.addAll(mLayoutMap.values()); - map.put(AndroidConstants.CLASS_VIEWGROUP, list); - - list = new ArrayList<IClassDescriptor>(); - list.addAll(mLayoutParamsMap.values()); - map.put(AndroidConstants.CLASS_VIEWGROUP_LAYOUTPARAMS, list); - - return map; - } - - /** - * Returns a {@link IAndroidClassLoader.IClassDescriptor} by its fully-qualified name. - * @param className the fully-qualified name of the class to return. - * @throws ClassNotFoundException - */ - public IClassDescriptor getClass(String className) throws ClassNotFoundException { - return mMap.get(className); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java deleted file mode 100644 index 33ec2bc..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java +++ /dev/null @@ -1,1319 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -/* - * References: - * org.eclipse.jdt.internal.ui.wizards.JavaProjectWizard - * org.eclipse.jdt.internal.ui.wizards.JavaProjectWizardFirstPage - */ - -package com.android.ide.eclipse.adt.wizards.newproject; - -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; -import com.android.sdklib.project.ProjectProperties; -import com.android.sdklib.project.ProjectProperties.PropertyType; -import com.android.sdkuilib.SdkTargetSelector; - -import org.eclipse.core.filesystem.URIUtil; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jdt.core.JavaConventions; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.osgi.util.TextProcessor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.DirectoryDialog; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Text; - -import java.io.File; -import java.io.FileFilter; -import java.net.URI; -import java.util.regex.Pattern; - -/** - * NewAndroidProjectCreationPage is a project creation page that provides the - * following fields: - * <ul> - * <li> Project name - * <li> SDK Target - * <li> Application name - * <li> Package name - * <li> Activity name - * </ul> - * Note: this class is public so that it can be accessed from unit tests. - * It is however an internal class. Its API may change without notice. - * It should semantically be considered as a private final class. - * Do not derive from this class. - */ -public class NewProjectCreationPage extends WizardPage { - - // constants - /** Initial value for all name fields (project, activity, application, package). Used - * whenever a value is requested before controls are created. */ - private static final String INITIAL_NAME = ""; //$NON-NLS-1$ - /** Initial value for the Create New Project radio; False means Create From Existing would be - * the default.*/ - private static final boolean INITIAL_CREATE_NEW_PROJECT = true; - /** Initial value for the Use Default Location check box. */ - private static final boolean INITIAL_USE_DEFAULT_LOCATION = true; - /** Initial value for the Create Activity check box. */ - private static final boolean INITIAL_CREATE_ACTIVITY = true; - - - /** Pattern for characters accepted in a project name. Since this will be used as a - * directory name, we're being a bit conservative on purpose. It cannot start with a space. */ - private static final Pattern sProjectNamePattern = Pattern.compile("^[\\w][\\w. -]*$"); //$NON-NLS-1$ - /** Last user-browsed location, static so that it be remembered for the whole session */ - private static String sCustomLocationOsPath = ""; //$NON-NLS-1$ - private static boolean sAutoComputeCustomLocation = true; - - private final int MSG_NONE = 0; - private final int MSG_WARNING = 1; - private final int MSG_ERROR = 2; - - private String mUserPackageName = ""; //$NON-NLS-1$ - private String mUserActivityName = ""; //$NON-NLS-1$ - private boolean mUserCreateActivityCheck = INITIAL_CREATE_ACTIVITY; - private String mSourceFolder = ""; //$NON-NLS-1$ - - // widgets - private Text mProjectNameField; - private Text mPackageNameField; - private Text mActivityNameField; - private Text mApplicationNameField; - private Button mCreateNewProjectRadio; - private Button mUseDefaultLocation; - private Label mLocationLabel; - private Text mLocationPathField; - private Button mBrowseButton; - private Button mCreateActivityCheck; - private Text mMinSdkVersionField; - private SdkTargetSelector mSdkTargetSelector; - - private boolean mInternalLocationPathUpdate; - protected boolean mInternalProjectNameUpdate; - protected boolean mInternalApplicationNameUpdate; - private boolean mInternalCreateActivityUpdate; - private boolean mInternalActivityNameUpdate; - protected boolean mProjectNameModifiedByUser; - protected boolean mApplicationNameModifiedByUser; - private boolean mInternalMinSdkVersionUpdate; - private boolean mMinSdkVersionModifiedByUser; - - - /** - * Creates a new project creation wizard page. - * - * @param pageName the name of this page - */ - public NewProjectCreationPage(String pageName) { - super(pageName); - setPageComplete(false); - } - - // --- Getters used by NewProjectWizard --- - - /** - * Returns the current project location path as entered by the user, or its - * anticipated initial value. Note that if the default has been returned the - * path in a project description used to create a project should not be set. - * - * @return the project location path or its anticipated initial value. - */ - public IPath getLocationPath() { - return new Path(getProjectLocation()); - } - - /** Returns the value of the project name field with leading and trailing spaces removed. */ - public String getProjectName() { - return mProjectNameField == null ? INITIAL_NAME : mProjectNameField.getText().trim(); - } - - /** Returns the value of the package name field with spaces trimmed. */ - public String getPackageName() { - return mPackageNameField == null ? INITIAL_NAME : mPackageNameField.getText().trim(); - } - - /** Returns the value of the activity name field with spaces trimmed. */ - public String getActivityName() { - return mActivityNameField == null ? INITIAL_NAME : mActivityNameField.getText().trim(); - } - - /** Returns the value of the min sdk version field with spaces trimmed. */ - public String getMinSdkVersion() { - return mMinSdkVersionField == null ? "" : mMinSdkVersionField.getText().trim(); - } - - /** Returns the value of the application name field with spaces trimmed. */ - public String getApplicationName() { - // Return the name of the activity as default application name. - return mApplicationNameField == null ? getActivityName() - : mApplicationNameField.getText().trim(); - - } - - /** Returns the value of the "Create New Project" radio. */ - public boolean isNewProject() { - return mCreateNewProjectRadio == null ? INITIAL_CREATE_NEW_PROJECT - : mCreateNewProjectRadio.getSelection(); - } - - /** Returns the value of the "Create Activity" checkbox. */ - public boolean isCreateActivity() { - return mCreateActivityCheck == null ? INITIAL_CREATE_ACTIVITY - : mCreateActivityCheck.getSelection(); - } - - /** Returns the value of the Use Default Location field. */ - public boolean useDefaultLocation() { - return mUseDefaultLocation == null ? INITIAL_USE_DEFAULT_LOCATION - : mUseDefaultLocation.getSelection(); - } - - /** Returns the internal source folder (for the "existing project" mode) or the default - * "src" constant. */ - public String getSourceFolder() { - if (isNewProject() || mSourceFolder == null || mSourceFolder.length() == 0) { - return SdkConstants.FD_SOURCES; - } else { - return mSourceFolder; - } - } - - /** Returns the current sdk target or null if none has been selected yet. */ - public IAndroidTarget getSdkTarget() { - return mSdkTargetSelector == null ? null : mSdkTargetSelector.getFirstSelected(); - } - - /** - * Overrides @DialogPage.setVisible(boolean) to put the focus in the project name when - * the dialog is made visible. - */ - @Override - public void setVisible(boolean visible) { - super.setVisible(visible); - if (visible) { - mProjectNameField.setFocus(); - } - } - - // --- UI creation --- - - /** - * Creates the top level control for this dialog page under the given parent - * composite. - * - * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) - */ - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setFont(parent.getFont()); - - initializeDialogUnits(parent); - - composite.setLayout(new GridLayout()); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createProjectNameGroup(composite); - createLocationGroup(composite); - createTargetGroup(composite); - createPropertiesGroup(composite); - - // Update state the first time - enableLocationWidgets(); - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - // Validate. This will complain about the first empty field. - setPageComplete(validatePage()); - } - - /** - * Creates the group for the project name: - * [label: "Project Name"] [text field] - * - * @param parent the parent composite - */ - private final void createProjectNameGroup(Composite parent) { - Composite group = new Composite(parent, SWT.NONE); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - group.setLayout(layout); - group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - // new project label - Label label = new Label(group, SWT.NONE); - label.setText("Project name:"); - label.setFont(parent.getFont()); - label.setToolTipText("Name of the Eclipse project to create. It cannot be empty."); - - // new project name entry field - mProjectNameField = new Text(group, SWT.BORDER); - GridData data = new GridData(GridData.FILL_HORIZONTAL); - mProjectNameField.setToolTipText("Name of the Eclipse project to create. It cannot be empty."); - mProjectNameField.setLayoutData(data); - mProjectNameField.setFont(parent.getFont()); - mProjectNameField.addListener(SWT.Modify, new Listener() { - public void handleEvent(Event event) { - if (!mInternalProjectNameUpdate) { - mProjectNameModifiedByUser = true; - } - updateLocationPathField(null); - } - }); - } - - - /** - * Creates the group for the Project options: - * [radio] Create new project - * [radio] Create project from existing sources - * [check] Use default location - * Location [text field] [browse button] - * - * @param parent the parent composite - */ - private final void createLocationGroup(Composite parent) { - Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); - // Layout has 4 columns of non-equal size - group.setLayout(new GridLayout()); - group.setLayoutData(new GridData(GridData.FILL_BOTH)); - group.setFont(parent.getFont()); - group.setText("Contents"); - - mCreateNewProjectRadio = new Button(group, SWT.RADIO); - mCreateNewProjectRadio.setText("Create new project in workspace"); - mCreateNewProjectRadio.setSelection(INITIAL_CREATE_NEW_PROJECT); - Button existing_project_radio = new Button(group, SWT.RADIO); - existing_project_radio.setText("Create project from existing source"); - existing_project_radio.setSelection(!INITIAL_CREATE_NEW_PROJECT); - - mUseDefaultLocation = new Button(group, SWT.CHECK); - mUseDefaultLocation.setText("Use default location"); - mUseDefaultLocation.setSelection(INITIAL_USE_DEFAULT_LOCATION); - - SelectionListener location_listener = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - enableLocationWidgets(); - extractNamesFromAndroidManifest(); - setPageComplete(validatePage()); - } - }; - - mCreateNewProjectRadio.addSelectionListener(location_listener); - existing_project_radio.addSelectionListener(location_listener); - mUseDefaultLocation.addSelectionListener(location_listener); - - Composite location_group = new Composite(group, SWT.NONE); - location_group.setLayout(new GridLayout(4, /* num columns */ - false /* columns of not equal size */)); - location_group.setLayoutData(new GridData(GridData.FILL_BOTH)); - location_group.setFont(parent.getFont()); - - mLocationLabel = new Label(location_group, SWT.NONE); - mLocationLabel.setText("Location:"); - - mLocationPathField = new Text(location_group, SWT.BORDER); - GridData data = new GridData(GridData.FILL, /* horizontal alignment */ - GridData.BEGINNING, /* vertical alignment */ - true, /* grabExcessHorizontalSpace */ - false, /* grabExcessVerticalSpace */ - 2, /* horizontalSpan */ - 1); /* verticalSpan */ - mLocationPathField.setLayoutData(data); - mLocationPathField.setFont(parent.getFont()); - mLocationPathField.addListener(SWT.Modify, new Listener() { - public void handleEvent(Event event) { - onLocationPathFieldModified(); - } - }); - - mBrowseButton = new Button(location_group, SWT.PUSH); - mBrowseButton.setText("Browse..."); - setButtonLayoutData(mBrowseButton); - mBrowseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - openDirectoryBrowser(); - } - }); - } - - /** - * Creates the target group. - * It only contains an SdkTargetSelector. - */ - private void createTargetGroup(Composite parent) { - Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); - // Layout has 1 column - group.setLayout(new GridLayout()); - group.setLayoutData(new GridData(GridData.FILL_BOTH)); - group.setFont(parent.getFont()); - group.setText("Target"); - - // get the targets from the sdk - IAndroidTarget[] targets = null; - if (Sdk.getCurrent() != null) { - targets = Sdk.getCurrent().getTargets(); - } - - mSdkTargetSelector = new SdkTargetSelector(group, targets, false /*multi-selection*/); - - // If there's only one target, select it - if (targets != null && targets.length == 1) { - mSdkTargetSelector.setSelection(targets[0]); - } - - mSdkTargetSelector.setSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onSdkTargetModified(); - updateLocationPathField(null); - setPageComplete(validatePage()); - } - }); - } - - /** - * Display a directory browser and update the location path field with the selected path - */ - private void openDirectoryBrowser() { - - String existing_dir = getLocationPathFieldValue(); - - // Disable the path if it doesn't exist - if (existing_dir.length() == 0) { - existing_dir = null; - } else { - File f = new File(existing_dir); - if (!f.exists()) { - existing_dir = null; - } - } - - DirectoryDialog dd = new DirectoryDialog(mLocationPathField.getShell()); - dd.setMessage("Browse for folder"); - dd.setFilterPath(existing_dir); - String abs_dir = dd.open(); - - if (abs_dir != null) { - updateLocationPathField(abs_dir); - extractNamesFromAndroidManifest(); - setPageComplete(validatePage()); - } - } - - /** - * Creates the group for the project properties: - * - Package name [text field] - * - Activity name [text field] - * - Application name [text field] - * - * @param parent the parent composite - */ - private final void createPropertiesGroup(Composite parent) { - // package specification group - Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - group.setLayout(layout); - group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - group.setFont(parent.getFont()); - group.setText("Properties"); - - // new application label - Label label = new Label(group, SWT.NONE); - label.setText("Application name:"); - label.setFont(parent.getFont()); - label.setToolTipText("Name of the Application. This is a free string. It can be empty."); - - // new application name entry field - mApplicationNameField = new Text(group, SWT.BORDER); - GridData data = new GridData(GridData.FILL_HORIZONTAL); - mApplicationNameField.setToolTipText("Name of the Application. This is a free string. It can be empty."); - mApplicationNameField.setLayoutData(data); - mApplicationNameField.setFont(parent.getFont()); - mApplicationNameField.addListener(SWT.Modify, new Listener() { - public void handleEvent(Event event) { - if (!mInternalApplicationNameUpdate) { - mApplicationNameModifiedByUser = true; - } - } - }); - - // new package label - label = new Label(group, SWT.NONE); - label.setText("Package name:"); - label.setFont(parent.getFont()); - label.setToolTipText("Namespace of the Package to create. This must be a Java namespace with at least two components."); - - // new package name entry field - mPackageNameField = new Text(group, SWT.BORDER); - data = new GridData(GridData.FILL_HORIZONTAL); - mPackageNameField.setToolTipText("Namespace of the Package to create. This must be a Java namespace with at least two components."); - mPackageNameField.setLayoutData(data); - mPackageNameField.setFont(parent.getFont()); - mPackageNameField.addListener(SWT.Modify, new Listener() { - public void handleEvent(Event event) { - onPackageNameFieldModified(); - } - }); - - // new activity label - mCreateActivityCheck = new Button(group, SWT.CHECK); - mCreateActivityCheck.setText("Create Activity:"); - mCreateActivityCheck.setToolTipText("Specifies if you want to create a default Activity."); - mCreateActivityCheck.setFont(parent.getFont()); - mCreateActivityCheck.setSelection(INITIAL_CREATE_ACTIVITY); - mCreateActivityCheck.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - onCreateActivityCheckModified(); - enableLocationWidgets(); - } - }); - - // new activity name entry field - mActivityNameField = new Text(group, SWT.BORDER); - data = new GridData(GridData.FILL_HORIZONTAL); - mActivityNameField.setToolTipText("Name of the Activity class to create. Must be a valid Java identifier."); - mActivityNameField.setLayoutData(data); - mActivityNameField.setFont(parent.getFont()); - mActivityNameField.addListener(SWT.Modify, new Listener() { - public void handleEvent(Event event) { - onActivityNameFieldModified(); - } - }); - - // min sdk version label - label = new Label(group, SWT.NONE); - label.setText("Min SDK Version:"); - label.setFont(parent.getFont()); - label.setToolTipText("The minimum SDK version number that the application requires. Must be an integer > 0. It can be empty."); - - // min sdk version entry field - mMinSdkVersionField = new Text(group, SWT.BORDER); - data = new GridData(GridData.FILL_HORIZONTAL); - label.setToolTipText("The minimum SDK version number that the application requires. Must be an integer > 0. It can be empty."); - mMinSdkVersionField.setLayoutData(data); - mMinSdkVersionField.setFont(parent.getFont()); - mMinSdkVersionField.addListener(SWT.Modify, new Listener() { - public void handleEvent(Event event) { - onMinSdkVersionFieldModified(); - setPageComplete(validatePage()); - } - }); - } - - - //--- Internal getters & setters ------------------ - - /** Returns the location path field value with spaces trimmed. */ - private String getLocationPathFieldValue() { - return mLocationPathField == null ? "" : mLocationPathField.getText().trim(); - } - - /** Returns the current project location, depending on the Use Default Location check box. */ - public String getProjectLocation() { - if (isNewProject() && useDefaultLocation()) { - return Platform.getLocation().toString(); - } else { - return getLocationPathFieldValue(); - } - } - - /** - * Creates a project resource handle for the current project name field - * value. - * <p> - * This method does not create the project resource; this is the - * responsibility of <code>IProject::create</code> invoked by the new - * project resource wizard. - * </p> - * - * @return the new project resource handle - */ - private IProject getProjectHandle() { - return ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName()); - } - - // --- UI Callbacks ---- - - /** - * Enables or disable the location widgets depending on the user selection: - * the location path is enabled when using the "existing source" mode (i.e. not new project) - * or in new project mode with the "use default location" turned off. - */ - private void enableLocationWidgets() { - boolean is_new_project = isNewProject(); - boolean use_default = useDefaultLocation(); - boolean location_enabled = !is_new_project || !use_default; - boolean create_activity = isCreateActivity(); - - mUseDefaultLocation.setEnabled(is_new_project); - - mLocationLabel.setEnabled(location_enabled); - mLocationPathField.setEnabled(location_enabled); - mBrowseButton.setEnabled(location_enabled); - - mPackageNameField.setEnabled(is_new_project); - mCreateActivityCheck.setEnabled(is_new_project); - mActivityNameField.setEnabled(is_new_project & create_activity); - - updateLocationPathField(null); - updatePackageAndActivityFields(); - } - - /** - * Updates the location directory path field. - * <br/> - * When custom user selection is enabled, use the abs_dir argument if not null and also - * save it internally. If abs_dir is null, restore the last saved abs_dir. This allows the - * user selection to be remembered when the user switches from default to custom. - * <br/> - * When custom user selection is disabled, use the workspace default location with the - * current project name. This does not change the internally cached abs_dir. - * - * @param abs_dir A new absolute directory path or null to use the default. - */ - private void updateLocationPathField(String abs_dir) { - boolean is_new_project = isNewProject(); - boolean use_default = useDefaultLocation(); - boolean custom_location = !is_new_project || !use_default; - - if (!mInternalLocationPathUpdate) { - mInternalLocationPathUpdate = true; - if (custom_location) { - if (abs_dir != null) { - // We get here if the user selected a directory with the "Browse" button. - // Disable auto-compute of the custom location unless the user selected - // the exact same path. - sAutoComputeCustomLocation = sAutoComputeCustomLocation && - abs_dir.equals(sCustomLocationOsPath); - sCustomLocationOsPath = TextProcessor.process(abs_dir); - } else if (sAutoComputeCustomLocation || - !new File(sCustomLocationOsPath).isDirectory()) { - // By default select the samples directory of the current target - IAndroidTarget target = getSdkTarget(); - if (target != null) { - sCustomLocationOsPath = target.getPath(IAndroidTarget.SAMPLES); - } - - // If we don't have a target, select the base directory of the - // "universal sdk". If we don't even have that, use a root drive. - if (sCustomLocationOsPath == null || sCustomLocationOsPath.length() == 0) { - if (Sdk.getCurrent() != null) { - sCustomLocationOsPath = Sdk.getCurrent().getSdkLocation(); - } else { - sCustomLocationOsPath = File.listRoots()[0].getAbsolutePath(); - } - } - } - if (!mLocationPathField.getText().equals(sCustomLocationOsPath)) { - mLocationPathField.setText(sCustomLocationOsPath); - } - } else { - String value = Platform.getLocation().append(getProjectName()).toString(); - value = TextProcessor.process(value); - if (!mLocationPathField.getText().equals(value)) { - mLocationPathField.setText(value); - } - } - setPageComplete(validatePage()); - mInternalLocationPathUpdate = false; - } - } - - /** - * The location path field is either modified internally (from updateLocationPathField) - * or manually by the user when the custom_location mode is not set. - * - * Ignore the internal modification. When modified by the user, memorize the choice and - * validate the page. - */ - private void onLocationPathFieldModified() { - if (!mInternalLocationPathUpdate) { - // When the updates doesn't come from updateLocationPathField, it must be the user - // editing the field manually, in which case we want to save the value internally - // and we disable auto-compute of the custom location (to avoid overriding the user - // value) - String newPath = getLocationPathFieldValue(); - sAutoComputeCustomLocation = sAutoComputeCustomLocation && - newPath.equals(sCustomLocationOsPath); - sCustomLocationOsPath = newPath; - extractNamesFromAndroidManifest(); - setPageComplete(validatePage()); - } - } - - /** - * The package name field is either modified internally (from extractNamesFromAndroidManifest) - * or manually by the user when the custom_location mode is not set. - * - * Ignore the internal modification. When modified by the user, memorize the choice and - * validate the page. - */ - private void onPackageNameFieldModified() { - if (isNewProject()) { - mUserPackageName = getPackageName(); - setPageComplete(validatePage()); - } - } - - /** - * The create activity checkbox is either modified internally (from - * extractNamesFromAndroidManifest) or manually by the user. - * - * Ignore the internal modification. When modified by the user, memorize the choice and - * validate the page. - */ - private void onCreateActivityCheckModified() { - if (isNewProject() && !mInternalCreateActivityUpdate) { - mUserCreateActivityCheck = isCreateActivity(); - } - setPageComplete(validatePage()); - } - - /** - * The activity name field is either modified internally (from extractNamesFromAndroidManifest) - * or manually by the user when the custom_location mode is not set. - * - * Ignore the internal modification. When modified by the user, memorize the choice and - * validate the page. - */ - private void onActivityNameFieldModified() { - if (isNewProject() && !mInternalActivityNameUpdate) { - mUserActivityName = getActivityName(); - setPageComplete(validatePage()); - } - } - - /** - * Called when the min sdk version field has been modified. - * - * Ignore the internal modifications. When modified by the user, try to match - * a target with the same API level. - */ - private void onMinSdkVersionFieldModified() { - if (mInternalMinSdkVersionUpdate) { - return; - } - - try { - int version = Integer.parseInt(getMinSdkVersion()); - - // Before changing, compare with the currently selected one, if any. - // There can be multiple targets with the same sdk api version, so don't change - // it if it's already at the right version. - IAndroidTarget curr_target = getSdkTarget(); - if (curr_target != null && curr_target.getApiVersionNumber() == version) { - return; - } - - for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { - if (target.getApiVersionNumber() == version) { - mSdkTargetSelector.setSelection(target); - break; - } - } - } catch (NumberFormatException e) { - // ignore - } - - mMinSdkVersionModifiedByUser = true; - } - - /** - * Called when an SDK target is modified. - * - * If the minSdkVersion field hasn't been modified by the user yet, we change it - * to reflect the sdk api level that has just been selected. - */ - private void onSdkTargetModified() { - IAndroidTarget target = getSdkTarget(); - - if (target != null && !mMinSdkVersionModifiedByUser) { - mInternalMinSdkVersionUpdate = true; - mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber())); - mInternalMinSdkVersionUpdate = false; - } - } - - /** - * Called when the radio buttons are changed between the "create new project" and the - * "use existing source" mode. This reverts the fields to whatever the user manually - * entered before. - */ - private void updatePackageAndActivityFields() { - if (isNewProject()) { - if (mUserPackageName.length() > 0 && - !mPackageNameField.getText().equals(mUserPackageName)) { - mPackageNameField.setText(mUserPackageName); - } - - if (mUserActivityName.length() > 0 && - !mActivityNameField.getText().equals(mUserActivityName)) { - mInternalActivityNameUpdate = true; - mActivityNameField.setText(mUserActivityName); - mInternalActivityNameUpdate = false; - } - - if (mUserCreateActivityCheck != mCreateActivityCheck.getSelection()) { - mInternalCreateActivityUpdate = true; - mCreateActivityCheck.setSelection(mUserCreateActivityCheck); - mInternalCreateActivityUpdate = false; - } - } - } - - /** - * Extract names from an android manifest. - * This is done only if the user selected the "use existing source" and a manifest xml file - * can actually be found in the custom user directory. - */ - private void extractNamesFromAndroidManifest() { - if (isNewProject()) { - return; - } - - String projectLocation = getProjectLocation(); - File f = new File(projectLocation); - if (!f.isDirectory()) { - return; - } - - Path path = new Path(f.getPath()); - String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString(); - AndroidManifestHelper manifest = new AndroidManifestHelper(osPath); - if (!manifest.exists()) { - return; - } - - String packageName = null; - String activityName = null; - String minSdkVersion = null; - try { - packageName = manifest.getPackageName(); - activityName = manifest.getActivityName(1); - minSdkVersion = manifest.getMinSdkVersion(); - } catch (Exception e) { - // ignore exceptions - } - - - if (packageName != null && packageName.length() > 0) { - mPackageNameField.setText(packageName); - } - - if (activityName != null && activityName.length() > 0) { - mInternalActivityNameUpdate = true; - mInternalCreateActivityUpdate = true; - mActivityNameField.setText(activityName); - mCreateActivityCheck.setSelection(true); - mInternalCreateActivityUpdate = false; - mInternalActivityNameUpdate = false; - - // If project name and application names are empty, use the activity - // name as a default. If the activity name has dots, it's a part of a - // package specification and only the last identifier must be used. - if (activityName.indexOf('.') != -1) { - String[] ids = activityName.split(AndroidConstants.RE_DOT); - activityName = ids[ids.length - 1]; - } - if (mProjectNameField.getText().length() == 0 || - !mProjectNameModifiedByUser) { - mInternalProjectNameUpdate = true; - mProjectNameField.setText(activityName); - mInternalProjectNameUpdate = false; - } - if (mApplicationNameField.getText().length() == 0 || - !mApplicationNameModifiedByUser) { - mInternalApplicationNameUpdate = true; - mApplicationNameField.setText(activityName); - mInternalApplicationNameUpdate = false; - } - } else { - mInternalActivityNameUpdate = true; - mInternalCreateActivityUpdate = true; - mActivityNameField.setText(""); //$NON-NLS-1$ - mCreateActivityCheck.setSelection(false); - mInternalCreateActivityUpdate = false; - mInternalActivityNameUpdate = false; - - // There is no activity name to use to fill in the project and application - // name. However if there's a package name, we can use this as a base. - if (packageName != null && packageName.length() > 0) { - // Package name is a java identifier, so it's most suitable for - // an application name. - - if (mApplicationNameField.getText().length() == 0 || - !mApplicationNameModifiedByUser) { - mInternalApplicationNameUpdate = true; - mApplicationNameField.setText(packageName); - mInternalApplicationNameUpdate = false; - } - - // For the project name, remove any dots - packageName = packageName.replace('.', '_'); - if (mProjectNameField.getText().length() == 0 || - !mProjectNameModifiedByUser) { - mInternalProjectNameUpdate = true; - mProjectNameField.setText(packageName); - mInternalProjectNameUpdate = false; - } - - } - } - - // Select the target matching the manifest's sdk or build properties, if any - boolean foundTarget = false; - - ProjectProperties p = ProjectProperties.create(projectLocation, null); - if (p != null) { - // Check the {build|default}.properties files if present - p.merge(PropertyType.BUILD).merge(PropertyType.DEFAULT); - String v = p.getProperty(ProjectProperties.PROPERTY_TARGET); - IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(v); - if (target != null) { - mSdkTargetSelector.setSelection(target); - foundTarget = true; - } - } - - if (!foundTarget && minSdkVersion != null) { - try { - int sdkVersion = Integer.parseInt(minSdkVersion); - - for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { - if (target.getApiVersionNumber() == sdkVersion) { - mSdkTargetSelector.setSelection(target); - foundTarget = true; - break; - } - } - } catch(NumberFormatException e) { - // ignore - } - } - - if (!foundTarget) { - for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { - if (projectLocation.startsWith(target.getLocation())) { - mSdkTargetSelector.setSelection(target); - foundTarget = true; - break; - } - } - } - - if (!foundTarget) { - mInternalMinSdkVersionUpdate = true; - mMinSdkVersionField.setText(minSdkVersion == null ? "" : minSdkVersion); //$NON-NLS-1$ - mInternalMinSdkVersionUpdate = false; - } - } - - /** - * Returns whether this page's controls currently all contain valid values. - * - * @return <code>true</code> if all controls are valid, and - * <code>false</code> if at least one is invalid - */ - protected boolean validatePage() { - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - - int status = validateProjectField(workspace); - if ((status & MSG_ERROR) == 0) { - status |= validateLocationPath(workspace); - } - if ((status & MSG_ERROR) == 0) { - status |= validateSdkTarget(); - } - if ((status & MSG_ERROR) == 0) { - status |= validatePackageField(); - } - if ((status & MSG_ERROR) == 0) { - status |= validateActivityField(); - } - if ((status & MSG_ERROR) == 0) { - status |= validateMinSdkVersionField(); - } - if ((status & MSG_ERROR) == 0) { - status |= validateSourceFolder(); - } - if (status == MSG_NONE) { - setStatus(null, MSG_NONE); - } - - // Return false if there's an error so that the finish button be disabled. - return (status & MSG_ERROR) == 0; - } - - /** - * Validates the project name field. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validateProjectField(IWorkspace workspace) { - // Validate project field - String projectFieldContents = getProjectName(); - if (projectFieldContents.length() == 0) { - return setStatus("Project name must be specified", MSG_ERROR); - } - - // Limit the project name to shell-agnostic characters since it will be used to - // generate the final package - if (!sProjectNamePattern.matcher(projectFieldContents).matches()) { - return setStatus("The project name must start with an alphanumeric characters, followed by one or more alphanumerics, digits, dots, dashes, underscores or spaces.", - MSG_ERROR); - } - - IStatus nameStatus = workspace.validateName(projectFieldContents, IResource.PROJECT); - if (!nameStatus.isOK()) { - return setStatus(nameStatus.getMessage(), MSG_ERROR); - } - - if (getProjectHandle().exists()) { - return setStatus("A project with that name already exists in the workspace", - MSG_ERROR); - } - - return MSG_NONE; - } - - /** - * Validates the location path field. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validateLocationPath(IWorkspace workspace) { - Path path = new Path(getProjectLocation()); - if (isNewProject()) { - if (!useDefaultLocation()) { - // If not using the default value validate the location. - URI uri = URIUtil.toURI(path.toOSString()); - IStatus locationStatus = workspace.validateProjectLocationURI(getProjectHandle(), - uri); - if (!locationStatus.isOK()) { - return setStatus(locationStatus.getMessage(), MSG_ERROR); - } else { - // The location is valid as far as Eclipse is concerned (i.e. mostly not - // an existing workspace project.) Check it either doesn't exist or is - // a directory that is empty. - File f = path.toFile(); - if (f.exists() && !f.isDirectory()) { - return setStatus("A directory name must be specified.", MSG_ERROR); - } else if (f.isDirectory()) { - // However if the directory exists, we should put a warning if it is not - // empty. We don't put an error (we'll ask the user again for confirmation - // before using the directory.) - String[] l = f.list(); - if (l.length != 0) { - return setStatus("The selected output directory is not empty.", - MSG_WARNING); - } - } - } - } else { - // Otherwise validate the path string is not empty - if (getProjectLocation().length() == 0) { - return setStatus("A directory name must be specified.", MSG_ERROR); - } - - File dest = path.append(getProjectName()).toFile(); - if (dest.exists()) { - return setStatus(String.format("There is already a file or directory named \"%1$s\" in the selected location.", - getProjectName()), MSG_ERROR); - } - } - } else { - // Must be an existing directory - File f = path.toFile(); - if (!f.isDirectory()) { - return setStatus("An existing directory name must be specified.", MSG_ERROR); - } - - // Check there's an android manifest in the directory - String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString(); - AndroidManifestHelper manifest = new AndroidManifestHelper(osPath); - if (!manifest.exists()) { - return setStatus( - String.format("File %1$s not found in %2$s.", - AndroidConstants.FN_ANDROID_MANIFEST, f.getName()), - MSG_ERROR); - } - - // Parse it and check the important fields. - String packageName = manifest.getPackageName(); - if (packageName == null || packageName.length() == 0) { - return setStatus( - String.format("No package name defined in %1$s.", osPath), - MSG_ERROR); - } - - String activityName = manifest.getActivityName(1); - if (activityName == null || activityName.length() == 0) { - // This is acceptable now as long as no activity needs to be created - if (isCreateActivity()) { - return setStatus( - String.format("No activity name defined in %1$s.", osPath), - MSG_ERROR); - } - } - - // If there's already a .project, tell the user to use import instead. - if (path.append(".project").toFile().exists()) { //$NON-NLS-1$ - return setStatus("An Eclipse project already exists in this directory. Consider using File > Import > Existing Project instead.", - MSG_WARNING); - } - } - - return MSG_NONE; - } - - /** - * Validates the sdk target choice. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validateSdkTarget() { - if (getSdkTarget() == null) { - return setStatus("An SDK Target must be specified.", MSG_ERROR); - } - return MSG_NONE; - } - - /** - * Validates the sdk target choice. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validateMinSdkVersionField() { - - // If the min sdk version is empty, it is always accepted. - if (getMinSdkVersion().length() == 0) { - return MSG_NONE; - } - - int version = -1; - try { - // If not empty, it must be a valid integer > 0 - version = Integer.parseInt(getMinSdkVersion()); - } catch (NumberFormatException e) { - // ignore - } - - if (version < 1) { - return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR); - } - - if (getSdkTarget() != null && getSdkTarget().getApiVersionNumber() != version) { - return setStatus("The API level for the selected SDK target does not match the Min SDK version.", - MSG_WARNING); - } - - return MSG_NONE; - } - - /** - * Validates the activity name field. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validateActivityField() { - // Disregard if not creating an activity - if (!isCreateActivity()) { - return MSG_NONE; - } - - // Validate activity field - String activityFieldContents = getActivityName(); - if (activityFieldContents.length() == 0) { - return setStatus("Activity name must be specified.", MSG_ERROR); - } - - // The activity field can actually contain part of a sub-package name - // or it can start with a dot "." to indicates it comes from the parent package name. - String packageName = ""; - int pos = activityFieldContents.lastIndexOf('.'); - if (pos >= 0) { - packageName = activityFieldContents.substring(0, pos); - if (packageName.startsWith(".")) { //$NON-NLS-1$ - packageName = packageName.substring(1); - } - - activityFieldContents = activityFieldContents.substring(pos + 1); - } - - // the activity field can contain a simple java identifier, or a - // package name or one that starts with a dot. So if it starts with a dot, - // ignore this dot -- the rest must look like a package name. - if (activityFieldContents.charAt(0) == '.') { - activityFieldContents = activityFieldContents.substring(1); - } - - // Check it's a valid activity string - int result = MSG_NONE; - IStatus status = JavaConventions.validateTypeVariableName(activityFieldContents, - "1.5", "1.5"); //$NON-NLS-1$ $NON-NLS-2$ - if (!status.isOK()) { - result = setStatus(status.getMessage(), - status.getSeverity() == IStatus.ERROR ? MSG_ERROR : MSG_WARNING); - } - - // Check it's a valid package string - if (result != MSG_ERROR && packageName.length() > 0) { - status = JavaConventions.validatePackageName(packageName, - "1.5", "1.5"); //$NON-NLS-1$ $NON-NLS-2$ - if (!status.isOK()) { - result = setStatus(status.getMessage() + " (in the activity name)", - status.getSeverity() == IStatus.ERROR ? MSG_ERROR : MSG_WARNING); - } - } - - - return result; - } - - /** - * Validates the package name field. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validatePackageField() { - // Validate package field - String packageFieldContents = getPackageName(); - if (packageFieldContents.length() == 0) { - return setStatus("Package name must be specified.", MSG_ERROR); - } - - // Check it's a valid package string - int result = MSG_NONE; - IStatus status = JavaConventions.validatePackageName(packageFieldContents, "1.5", "1.5"); //$NON-NLS-1$ $NON-NLS-2$ - if (!status.isOK()) { - result = setStatus(status.getMessage(), - status.getSeverity() == IStatus.ERROR ? MSG_ERROR : MSG_WARNING); - } - - // The Android Activity Manager does not accept packages names with only one - // identifier. Check the package name has at least one dot in them (the previous rule - // validated that if such a dot exist, it's not the first nor last characters of the - // string.) - if (result != MSG_ERROR && packageFieldContents.indexOf('.') == -1) { - return setStatus("Package name must have at least two identifiers.", MSG_ERROR); - } - - return result; - } - - /** - * Validates that an existing project actually has a source folder. - * - * For project in "use existing source" mode, this tries to find the source folder. - * A source folder should be just under the project directory and it should have all - * the directories composing the package+activity name. - * - * As a side effect, it memorizes the source folder in mSourceFolder. - * - * TODO: support multiple source folders for multiple activities. - * - * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. - */ - private int validateSourceFolder() { - // This check does nothing when creating a new project. - // This check is also useless when no activity is present or created. - if (isNewProject() || !isCreateActivity()) { - return MSG_NONE; - } - - String osTarget = getActivityName(); - - if (osTarget.indexOf('.') == -1) { - osTarget = getPackageName() + File.separator + osTarget; - } else if (osTarget.indexOf('.') == 0) { - osTarget = getPackageName() + osTarget; - } - osTarget = osTarget.replace('.', File.separatorChar) + AndroidConstants.DOT_JAVA; - - String projectPath = getProjectLocation(); - File projectDir = new File(projectPath); - File[] all_dirs = projectDir.listFiles(new FileFilter() { - public boolean accept(File pathname) { - return pathname.isDirectory(); - } - }); - for (File f : all_dirs) { - Path path = new Path(f.getAbsolutePath()); - File java_activity = path.append(osTarget).toFile(); - if (java_activity.isFile()) { - mSourceFolder = f.getName(); - return MSG_NONE; - } - } - - if (all_dirs.length > 0) { - return setStatus( - String.format("%1$s can not be found under %2$s.", osTarget, projectPath), - MSG_ERROR); - } else { - return setStatus( - String.format("No source folders can be found in %1$s.", projectPath), - MSG_ERROR); - } - } - - /** - * Sets the error message for the wizard with the given message icon. - * - * @param message The wizard message type, one of MSG_ERROR or MSG_WARNING. - * @return As a convenience, always returns messageType so that the caller can return - * immediately. - */ - private int setStatus(String message, int messageType) { - if (message == null) { - setErrorMessage(null); - setMessage(null); - } else if (!message.equals(getMessage())) { - setMessage(message, messageType == MSG_WARNING ? WizardPage.WARNING : WizardPage.ERROR); - } - return messageType; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java deleted file mode 100644 index 607159a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java +++ /dev/null @@ -1,729 +0,0 @@ -/* - * Copyright (C) 2007 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.wizards.newproject; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.project.AndroidNature; -import com.android.ide.eclipse.adt.project.ProjectHelper; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceStatus; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.ui.actions.OpenJavaPerspectiveAction; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.ui.INewWizard; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.actions.WorkspaceModifyOperation; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -/** - * A "New Android Project" Wizard. - * <p/> - * Note: this class is public so that it can be accessed from unit tests. - * It is however an internal class. Its API may change without notice. - * It should semantically be considered as a private final class. - * Do not derive from this class. - - */ -public class NewProjectWizard extends Wizard implements INewWizard { - - private static final String PARAM_SDK_TOOLS_DIR = "ANDROID_SDK_TOOLS"; //$NON-NLS-1$ - private static final String PARAM_ACTIVITY = "ACTIVITY_NAME"; //$NON-NLS-1$ - private static final String PARAM_APPLICATION = "APPLICATION_NAME"; //$NON-NLS-1$ - private static final String PARAM_PACKAGE = "PACKAGE"; //$NON-NLS-1$ - private static final String PARAM_PROJECT = "PROJECT_NAME"; //$NON-NLS-1$ - private static final String PARAM_STRING_NAME = "STRING_NAME"; //$NON-NLS-1$ - private static final String PARAM_STRING_CONTENT = "STRING_CONTENT"; //$NON-NLS-1$ - private static final String PARAM_IS_NEW_PROJECT = "IS_NEW_PROJECT"; //$NON-NLS-1$ - private static final String PARAM_SRC_FOLDER = "SRC_FOLDER"; //$NON-NLS-1$ - private static final String PARAM_SDK_TARGET = "SDK_TARGET"; //$NON-NLS-1$ - private static final String PARAM_MIN_SDK_VERSION = "MIN_SDK_VERSION"; //$NON-NLS-1$ - - private static final String PH_ACTIVITIES = "ACTIVITIES"; //$NON-NLS-1$ - private static final String PH_USES_SDK = "USES-SDK"; //$NON-NLS-1$ - private static final String PH_INTENT_FILTERS = "INTENT_FILTERS"; //$NON-NLS-1$ - private static final String PH_STRINGS = "STRINGS"; //$NON-NLS-1$ - - private static final String BIN_DIRECTORY = - SdkConstants.FD_OUTPUT + AndroidConstants.WS_SEP; - private static final String RES_DIRECTORY = - SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP; - private static final String ASSETS_DIRECTORY = - SdkConstants.FD_ASSETS + AndroidConstants.WS_SEP; - private static final String DRAWABLE_DIRECTORY = - SdkConstants.FD_DRAWABLE + AndroidConstants.WS_SEP; - private static final String LAYOUT_DIRECTORY = - SdkConstants.FD_LAYOUT + AndroidConstants.WS_SEP; - private static final String VALUES_DIRECTORY = - SdkConstants.FD_VALUES + AndroidConstants.WS_SEP; - - private static final String TEMPLATES_DIRECTORY = "templates/"; //$NON-NLS-1$ - private static final String TEMPLATE_MANIFEST = TEMPLATES_DIRECTORY - + "AndroidManifest.template"; //$NON-NLS-1$ - private static final String TEMPLATE_ACTIVITIES = TEMPLATES_DIRECTORY - + "activity.template"; //$NON-NLS-1$ - private static final String TEMPLATE_USES_SDK = TEMPLATES_DIRECTORY - + "uses-sdk.template"; //$NON-NLS-1$ - private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY - + "launcher_intent_filter.template"; //$NON-NLS-1$ - - private static final String TEMPLATE_STRINGS = TEMPLATES_DIRECTORY - + "strings.template"; //$NON-NLS-1$ - private static final String TEMPLATE_STRING = TEMPLATES_DIRECTORY - + "string.template"; //$NON-NLS-1$ - private static final String ICON = "icon.png"; //$NON-NLS-1$ - - private static final String STRINGS_FILE = "strings.xml"; //$NON-NLS-1$ - - private static final String STRING_RSRC_PREFIX = "@string/"; //$NON-NLS-1$ - private static final String STRING_APP_NAME = "app_name"; //$NON-NLS-1$ - private static final String STRING_HELLO_WORLD = "hello"; //$NON-NLS-1$ - - private static final String[] DEFAULT_DIRECTORIES = new String[] { - BIN_DIRECTORY, RES_DIRECTORY, ASSETS_DIRECTORY }; - private static final String[] RES_DIRECTORIES = new String[] { - DRAWABLE_DIRECTORY, LAYOUT_DIRECTORY, VALUES_DIRECTORY}; - - private static final String PROJECT_LOGO_LARGE = "icons/android_large.png"; //$NON-NLS-1$ - private static final String JAVA_ACTIVITY_TEMPLATE = "java_file.template"; //$NON-NLS-1$ - private static final String LAYOUT_TEMPLATE = "layout.template"; //$NON-NLS-1$ - private static final String MAIN_LAYOUT_XML = "main.xml"; //$NON-NLS-1$ - - protected static final String MAIN_PAGE_NAME = "newAndroidProjectPage"; //$NON-NLS-1$ - - private NewProjectCreationPage mMainPage; - - /** - * Initializes this creation wizard using the passed workbench and object - * selection. Inherited from org.eclipse.ui.IWorkbenchWizard - */ - public void init(IWorkbench workbench, IStructuredSelection selection) { - setHelpAvailable(false); // TODO have help - setWindowTitle("New Android Project"); - setImageDescriptor(); - - mMainPage = createMainPage(); - mMainPage.setTitle("New Android Project"); - mMainPage.setDescription("Creates a new Android Project resource."); - } - - /** - * Creates the wizard page. - * <p/> - * Please do NOT override this method. - * <p/> - * This is protected so that it can be overridden by unit tests. - * However the contract of this class is private and NO ATTEMPT will be made - * to maintain compatibility between different versions of the plugin. - */ - protected NewProjectCreationPage createMainPage() { - return new NewProjectCreationPage(MAIN_PAGE_NAME); - } - - // -- Methods inherited from org.eclipse.jface.wizard.Wizard -- - // The Wizard class implements most defaults and boilerplate code needed by - // IWizard - - /** - * Adds pages to this wizard. - */ - @Override - public void addPages() { - addPage(mMainPage); - } - - /** - * Performs any actions appropriate in response to the user having pressed - * the Finish button, or refuse if finishing now is not permitted: here, it - * actually creates the workspace project and then switch to the Java - * perspective. - * - * @return True - */ - @Override - public boolean performFinish() { - if (!createAndroidProject()) { - return false; - } - - // Open the default Java Perspective - OpenJavaPerspectiveAction action = new OpenJavaPerspectiveAction(); - action.run(); - return true; - } - - // -- Custom Methods -- - - /** - * Before actually creating the project for a new project (as opposed to using an - * existing project), we check if the target location is a directory that either does - * not exist or is empty. - * - * If it's not empty, ask the user for confirmation. - * - * @param destination The destination folder where the new project is to be created. - * @return True if the destination doesn't exist yet or is an empty directory or is - * accepted by the user. - */ - private boolean validateNewProjectLocationIsEmpty(IPath destination) { - File f = new File(destination.toOSString()); - if (f.isDirectory() && f.list().length > 0) { - return AdtPlugin.displayPrompt("New Android Project", - "You are going to create a new Android Project in an existing, non-empty, directory. Are you sure you want to proceed?"); - } - return true; - } - - /** - * Creates the android project. - * @return True if the project could be created. - */ - private boolean createAndroidProject() { - IWorkspace workspace = ResourcesPlugin.getWorkspace(); - final IProject project = workspace.getRoot().getProject(mMainPage.getProjectName()); - final IProjectDescription description = workspace.newProjectDescription(project.getName()); - - final Map<String, Object> parameters = new HashMap<String, Object>(); - parameters.put(PARAM_PROJECT, mMainPage.getProjectName()); - parameters.put(PARAM_PACKAGE, mMainPage.getPackageName()); - parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME); - parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder()); - parameters.put(PARAM_IS_NEW_PROJECT, mMainPage.isNewProject()); - parameters.put(PARAM_SRC_FOLDER, mMainPage.getSourceFolder()); - parameters.put(PARAM_SDK_TARGET, mMainPage.getSdkTarget()); - parameters.put(PARAM_MIN_SDK_VERSION, mMainPage.getMinSdkVersion()); - - if (mMainPage.isCreateActivity()) { - // An activity name can be of the form ".package.Class" or ".Class". - // The initial dot is ignored, as it is always added later in the templates. - String activityName = mMainPage.getActivityName(); - if (activityName.startsWith(".")) { //$NON-NLS-1$ - activityName = activityName.substring(1); - } - parameters.put(PARAM_ACTIVITY, activityName); - } - - // create a dictionary of string that will contain name+content. - // we'll put all the strings into values/strings.xml - final HashMap<String, String> stringDictionary = new HashMap<String, String>(); - stringDictionary.put(STRING_APP_NAME, mMainPage.getApplicationName()); - - IPath path = mMainPage.getLocationPath(); - IPath defaultLocation = Platform.getLocation(); - if (!path.equals(defaultLocation)) { - description.setLocation(path); - } - - if (mMainPage.isNewProject() && !mMainPage.useDefaultLocation() && - !validateNewProjectLocationIsEmpty(path)) { - return false; - } - - // Create a monitored operation to create the actual project - WorkspaceModifyOperation op = new WorkspaceModifyOperation() { - @Override - protected void execute(IProgressMonitor monitor) throws InvocationTargetException { - createProjectAsync(project, description, monitor, parameters, stringDictionary); - } - }; - - // Run the operation in a different thread - runAsyncOperation(op); - return true; - } - - /** - * Runs the operation in a different thread and display generated - * exceptions. - * - * @param op The asynchronous operation to run. - */ - private void runAsyncOperation(WorkspaceModifyOperation op) { - try { - getContainer().run(true /* fork */, true /* cancelable */, op); - } catch (InvocationTargetException e) { - // The runnable threw an exception - Throwable t = e.getTargetException(); - if (t instanceof CoreException) { - CoreException core = (CoreException) t; - if (core.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) { - // The error indicates the file system is not case sensitive - // and there's a resource with a similar name. - MessageDialog.openError(getShell(), "Error", "Error: Case Variant Exists"); - } else { - ErrorDialog.openError(getShell(), "Error", null, core.getStatus()); - } - } else { - // Some other kind of exception - MessageDialog.openError(getShell(), "Error", t.getMessage()); - } - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - /** - * Creates the actual project, sets its nature and adds the required folders - * and files to it. This is run asynchronously in a different thread. - * - * @param project The project to create. - * @param description A description of the project. - * @param monitor An existing monitor. - * @param parameters Template parameters. - * @param stringDictionary String definition. - * @throws InvocationTargetException to wrap any unmanaged exception and - * return it to the calling thread. The method can fail if it fails - * to create or modify the project or if it is canceled by the user. - */ - private void createProjectAsync(IProject project, IProjectDescription description, - IProgressMonitor monitor, Map<String, Object> parameters, - Map<String, String> stringDictionary) - throws InvocationTargetException { - monitor.beginTask("Create Android Project", 100); - try { - // Create project and open it - project.create(description, new SubProgressMonitor(monitor, 10)); - if (monitor.isCanceled()) throw new OperationCanceledException(); - project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10)); - - // Add the Java and android nature to the project - AndroidNature.setupProjectNatures(project, monitor); - - // Create folders in the project if they don't already exist - addDefaultDirectories(project, AndroidConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor); - String[] sourceFolder = new String[] { (String) parameters.get(PARAM_SRC_FOLDER) }; - addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolder, monitor); - - // Create the resource folders in the project if they don't already exist. - addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor); - - // Setup class path - IJavaProject javaProject = JavaCore.create(project); - setupSourceFolder(javaProject, sourceFolder[0], monitor); - - if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) { - // Create files in the project if they don't already exist - addManifest(project, parameters, stringDictionary, monitor); - - // add the default app icon - addIcon(project, monitor); - - // Create the default package components - addSampleCode(project, sourceFolder[0], parameters, stringDictionary, monitor); - - // add the string definition file if needed - if (stringDictionary.size() > 0) { - addStringDictionaryFile(project, stringDictionary, monitor); - } - - // Set output location - javaProject.setOutputLocation(project.getFolder(BIN_DIRECTORY).getFullPath(), - monitor); - } - - Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET)); - - // Fix the project to make sure all properties are as expected. - // Necessary for existing projects and good for new ones to. - ProjectHelper.fixProject(project); - - } catch (CoreException e) { - throw new InvocationTargetException(e); - } catch (IOException e) { - throw new InvocationTargetException(e); - } finally { - monitor.done(); - } - } - - /** - * Adds default directories to the project. - * - * @param project The Java Project to update. - * @param parentFolder The path of the parent folder. Must end with a - * separator. - * @param folders Folders to be added. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to create the directories in - * the project. - */ - private void addDefaultDirectories(IProject project, String parentFolder, - String[] folders, IProgressMonitor monitor) throws CoreException { - for (String name : folders) { - if (name.length() > 0) { - IFolder folder = project.getFolder(parentFolder + name); - if (!folder.exists()) { - folder.create(true /* force */, true /* local */, - new SubProgressMonitor(monitor, 10)); - } - } - } - } - - /** - * Adds the manifest to the project. - * - * @param project The Java Project to update. - * @param parameters Template Parameters. - * @param stringDictionary String List to be added to a string definition - * file. This map will be filled by this method. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - * @throws IOException if the method fails to create the files in the - * project. - */ - private void addManifest(IProject project, Map<String, Object> parameters, - Map<String, String> stringDictionary, IProgressMonitor monitor) - throws CoreException, IOException { - - // get IFile to the manifest and check if it's not already there. - IFile file = project.getFile(AndroidConstants.FN_ANDROID_MANIFEST); - if (!file.exists()) { - - // Read manifest template - String manifestTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_MANIFEST); - - // Replace all keyword parameters - manifestTemplate = replaceParameters(manifestTemplate, parameters); - - if (parameters.containsKey(PARAM_ACTIVITY)) { - // now get the activity template - String activityTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_ACTIVITIES); - - // Replace all keyword parameters to make main activity. - String activities = replaceParameters(activityTemplate, parameters); - - // set the intent. - String intent = AdtPlugin.readEmbeddedTextFile(TEMPLATE_INTENT_LAUNCHER); - - // set the intent to the main activity - activities = activities.replaceAll(PH_INTENT_FILTERS, intent); - - // set the activity(ies) in the manifest - manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities); - } else { - // remove the activity(ies) from the manifest - manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, ""); - } - - String minSdkVersion = (String) parameters.get(PARAM_MIN_SDK_VERSION); - if (minSdkVersion != null && minSdkVersion.length() > 0) { - String usesSdkTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_USES_SDK); - String usesSdk = replaceParameters(usesSdkTemplate, parameters); - manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, usesSdk); - } else { - manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, ""); - } - - // Save in the project as UTF-8 - InputStream stream = new ByteArrayInputStream( - manifestTemplate.getBytes("UTF-8")); //$NON-NLS-1$ - file.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - - /** - * Adds the string resource file. - * - * @param project The Java Project to update. - * @param strings The list of strings to be added to the string file. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - * @throws IOException if the method fails to create the files in the - * project. - */ - private void addStringDictionaryFile(IProject project, - Map<String, String> strings, IProgressMonitor monitor) - throws CoreException, IOException { - - // create the IFile object and check if the file doesn't already exist. - IFile file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP - + VALUES_DIRECTORY + AndroidConstants.WS_SEP + STRINGS_FILE); - if (!file.exists()) { - // get the Strings.xml template - String stringDefinitionTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_STRINGS); - - // get the template for one string - String stringTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_STRING); - - // get all the string names - Set<String> stringNames = strings.keySet(); - - // loop on it and create the string definitions - StringBuilder stringNodes = new StringBuilder(); - for (String key : stringNames) { - // get the value from the key - String value = strings.get(key); - - // place them in the template - String stringDef = stringTemplate.replace(PARAM_STRING_NAME, key); - stringDef = stringDef.replace(PARAM_STRING_CONTENT, value); - - // append to the other string - if (stringNodes.length() > 0) { - stringNodes.append("\n"); - } - stringNodes.append(stringDef); - } - - // put the string nodes in the Strings.xml template - stringDefinitionTemplate = stringDefinitionTemplate.replace(PH_STRINGS, - stringNodes.toString()); - - // write the file as UTF-8 - InputStream stream = new ByteArrayInputStream( - stringDefinitionTemplate.getBytes("UTF-8")); //$NON-NLS-1$ - file.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - - - /** - * Adds default application icon to the project. - * - * @param project The Java Project to update. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - */ - private void addIcon(IProject project, IProgressMonitor monitor) - throws CoreException { - IFile file = project.getFile(RES_DIRECTORY + AndroidConstants.WS_SEP - + DRAWABLE_DIRECTORY + AndroidConstants.WS_SEP + ICON); - if (!file.exists()) { - // read the content from the template - byte[] buffer = AdtPlugin.readEmbeddedFile(TEMPLATES_DIRECTORY + ICON); - - // if valid - if (buffer != null) { - // Save in the project - InputStream stream = new ByteArrayInputStream(buffer); - file.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - } - } - - /** - * Creates the package folder and copies the sample code in the project. - * - * @param project The Java Project to update. - * @param parameters Template Parameters. - * @param stringDictionary String List to be added to a string definition - * file. This map will be filled by this method. - * @param monitor An existing monitor. - * @throws CoreException if the method fails to update the project. - * @throws IOException if the method fails to create the files in the - * project. - */ - private void addSampleCode(IProject project, String sourceFolder, - Map<String, Object> parameters, Map<String, String> stringDictionary, - IProgressMonitor monitor) throws CoreException, IOException { - // create the java package directories. - IFolder pkgFolder = project.getFolder(sourceFolder); - String packageName = (String) parameters.get(PARAM_PACKAGE); - - // The PARAM_ACTIVITY key will be absent if no activity should be created, - // in which case activityName will be null. - String activityName = (String) parameters.get(PARAM_ACTIVITY); - Map<String, Object> java_activity_parameters = parameters; - if (activityName != null) { - if (activityName.indexOf('.') >= 0) { - // There are package names in the activity name. Transform packageName to add - // those sub packages and remove them from activityName. - packageName += "." + activityName; //$NON-NLS-1$ - int pos = packageName.lastIndexOf('.'); - activityName = packageName.substring(pos + 1); - packageName = packageName.substring(0, pos); - - // Also update the values used in the JAVA_FILE_TEMPLATE below - // (but not the ones from the manifest so don't change the caller's dictionary) - java_activity_parameters = new HashMap<String, Object>(parameters); - java_activity_parameters.put(PARAM_PACKAGE, packageName); - java_activity_parameters.put(PARAM_ACTIVITY, activityName); - } - } - - String[] components = packageName.split(AndroidConstants.RE_DOT); - for (String component : components) { - pkgFolder = pkgFolder.getFolder(component); - if (!pkgFolder.exists()) { - pkgFolder.create(true /* force */, true /* local */, - new SubProgressMonitor(monitor, 10)); - } - } - - if (activityName != null) { - // create the main activity Java file - String activityJava = activityName + AndroidConstants.DOT_JAVA; - IFile file = pkgFolder.getFile(activityJava); - if (!file.exists()) { - copyFile(JAVA_ACTIVITY_TEMPLATE, file, java_activity_parameters, monitor); - } - } - - // create the layout file - IFolder layoutfolder = project.getFolder(RES_DIRECTORY).getFolder(LAYOUT_DIRECTORY); - IFile file = layoutfolder.getFile(MAIN_LAYOUT_XML); - if (!file.exists()) { - copyFile(LAYOUT_TEMPLATE, file, parameters, monitor); - if (activityName != null) { - stringDictionary.put(STRING_HELLO_WORLD, "Hello World, " + activityName + "!"); - } else { - stringDictionary.put(STRING_HELLO_WORLD, "Hello World!"); - } - } - } - - /** - * Adds the given folder to the project's class path. - * - * @param javaProject The Java Project to update. - * @param sourceFolder Template Parameters. - * @param monitor An existing monitor. - * @throws JavaModelException if the classpath could not be set. - */ - private void setupSourceFolder(IJavaProject javaProject, String sourceFolder, - IProgressMonitor monitor) throws JavaModelException { - IProject project = javaProject.getProject(); - - // Add "src" to class path - IFolder srcFolder = project.getFolder(sourceFolder); - - IClasspathEntry[] entries = javaProject.getRawClasspath(); - entries = removeSourceClasspath(entries, srcFolder); - entries = removeSourceClasspath(entries, srcFolder.getParent()); - - entries = ProjectHelper.addEntryToClasspath(entries, - JavaCore.newSourceEntry(srcFolder.getFullPath())); - - javaProject.setRawClasspath(entries, new SubProgressMonitor(monitor, 10)); - } - - - /** - * Removes the corresponding source folder from the class path entries if - * found. - * - * @param entries The class path entries to read. A copy will be returned. - * @param folder The parent source folder to remove. - * @return A new class path entries array. - */ - private IClasspathEntry[] removeSourceClasspath(IClasspathEntry[] entries, IContainer folder) { - if (folder == null) { - return entries; - } - IClasspathEntry source = JavaCore.newSourceEntry(folder.getFullPath()); - int n = entries.length; - for (int i = n - 1; i >= 0; i--) { - if (entries[i].equals(source)) { - IClasspathEntry[] newEntries = new IClasspathEntry[n - 1]; - if (i > 0) System.arraycopy(entries, 0, newEntries, 0, i); - if (i < n - 1) System.arraycopy(entries, i + 1, newEntries, i, n - i - 1); - n--; - entries = newEntries; - } - } - return entries; - } - - - /** - * Copies the given file from our resource folder to the new project. - * Expects the file to the US-ASCII or UTF-8 encoded. - * - * @throws CoreException from IFile if failing to create the new file. - * @throws MalformedURLException from URL if failing to interpret the URL. - * @throws FileNotFoundException from RandomAccessFile. - * @throws IOException from RandomAccessFile.length() if can't determine the - * length. - */ - private void copyFile(String resourceFilename, IFile destFile, - Map<String, Object> parameters, IProgressMonitor monitor) - throws CoreException, IOException { - - // Read existing file. - String template = AdtPlugin.readEmbeddedTextFile( - TEMPLATES_DIRECTORY + resourceFilename); - - // Replace all keyword parameters - template = replaceParameters(template, parameters); - - // Save in the project as UTF-8 - InputStream stream = new ByteArrayInputStream(template.getBytes("UTF-8")); //$NON-NLS-1$ - destFile.create(stream, false /* force */, new SubProgressMonitor(monitor, 10)); - } - - /** - * Returns an image descriptor for the wizard logo. - */ - private void setImageDescriptor() { - ImageDescriptor desc = AdtPlugin.getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - } - - /** - * Replaces placeholders found in a string with values. - * - * @param str the string to search for placeholders. - * @param parameters a map of <placeholder, Value> to search for in the string - * @return A new String object with the placeholder replaced by the values. - */ - private String replaceParameters(String str, Map<String, Object> parameters) { - for (Entry<String, Object> entry : parameters.entrySet()) { - if (entry.getValue() instanceof String) { - str = str.replaceAll(entry.getKey(), (String) entry.getValue()); - } - } - - return str; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java deleted file mode 100644 index b1c57a6..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2007 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.common; - -import com.android.sdklib.SdkConstants; - -import java.io.File; -import java.util.regex.Pattern; - -/** - * Constant definition class.<br> - * <br> - * Most constants have a prefix defining the content. - * <ul> - * <li><code>WS_</code> Workspace path constant. Those are absolute paths, - * from the project root.</li> - * <li><code>OS_</code> OS path constant. These paths are different depending on the platform.</li> - * <li><code>FN_</code> File name constant.</li> - * <li><code>FD_</code> Folder name constant.</li> - * <li><code>MARKER_</code> Resource Marker Ids constant.</li> - * <li><code>EXT_</code> File extension constant. This does NOT include a dot.</li> - * <li><code>DOT_</code> File extension constant. This start with a dot.</li> - * <li><code>RE_</code> Regexp constant.</li> - * <li><code>NS_</code> Namespace constant.</li> - * <li><code>CLASS_</code> Fully qualified class name.</li> - * </ul> - * - */ -public class AndroidConstants { - /** - * The old Editors Plugin ID. It is still used in some places for compatibility. - * Please do not use for new features. - */ - public static final String EDITORS_NAMESPACE = "com.android.ide.eclipse.editors"; // $NON-NLS-1$ - - /** Nature of android projects */ - public final static String NATURE = "com.android.ide.eclipse.adt.AndroidNature"; //$NON-NLS-1$ - - /** Separator for workspace path, i.e. "/". */ - public final static String WS_SEP = "/"; //$NON-NLS-1$ - /** Separator character for workspace path, i.e. '/'. */ - public final static char WS_SEP_CHAR = '/'; - - /** Extension of the Application package Files, i.e. "apk". */ - public final static String EXT_ANDROID_PACKAGE = "apk"; //$NON-NLS-1$ - /** Extension of java files, i.e. "java" */ - public final static String EXT_JAVA = "java"; //$NON-NLS-1$ - /** Extension of compiled java files, i.e. "class" */ - public final static String EXT_CLASS = "class"; //$NON-NLS-1$ - /** Extension of xml files, i.e. "xml" */ - public final static String EXT_XML = "xml"; //$NON-NLS-1$ - /** Extension of jar files, i.e. "jar" */ - public final static String EXT_JAR = "jar"; //$NON-NLS-1$ - /** Extension of aidl files, i.e. "aidl" */ - public final static String EXT_AIDL = "aidl"; //$NON-NLS-1$ - /** Extension of native libraries, i.e. "so" */ - public final static String EXT_NATIVE_LIB = "so"; //$NON-NLS-1$ - - private final static String DOT = "."; //$NON-NLS-1$ - - /** Dot-Extension of the Application package Files, i.e. ".apk". */ - public final static String DOT_ANDROID_PACKAGE = DOT + EXT_ANDROID_PACKAGE; - /** Dot-Extension of java files, i.e. ".java" */ - public final static String DOT_JAVA = DOT + EXT_JAVA; - /** Dot-Extension of compiled java files, i.e. ".class" */ - public final static String DOT_CLASS = DOT + EXT_CLASS; - /** Dot-Extension of xml files, i.e. ".xml" */ - public final static String DOT_XML = DOT + EXT_XML; - /** Dot-Extension of jar files, i.e. ".jar" */ - public final static String DOT_JAR = DOT + EXT_JAR; - /** Dot-Extension of aidl files, i.e. ".aidl" */ - public final static String DOT_AIDL = DOT + EXT_AIDL; - - /** Name of the manifest file, i.e. "AndroidManifest.xml". */ - public static final String FN_ANDROID_MANIFEST = "AndroidManifest.xml"; //$NON-NLS-1$ - public static final String FN_PROJECT_AIDL = "project.aidl"; //$NON-NLS-1$ - - /** Name of the android sources directory */ - public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$ - - /** Resource java class filename, i.e. "R.java" */ - public final static String FN_RESOURCE_CLASS = "R.java"; //$NON-NLS-1$ - /** Resource class file filename, i.e. "R.class" */ - public final static String FN_COMPILED_RESOURCE_CLASS = "R.class"; //$NON-NLS-1$ - /** Manifest java class filename, i.e. "Manifest.java" */ - public final static String FN_MANIFEST_CLASS = "Manifest.java"; //$NON-NLS-1$ - /** Dex conversion output filname, i.e. "classes.dex" */ - public final static String FN_CLASSES_DEX = "classes.dex"; //$NON-NLS-1$ - /** Temporary packaged resources file name, i.e. "resources.ap_" */ - public final static String FN_RESOURCES_AP_ = "resources.ap_"; //$NON-NLS-1$ - /** Temporary packaged resources file name for a specific set of configuration */ - public final static String FN_RESOURCES_S_AP_ = "resources-%s.ap_"; //$NON-NLS-1$ - public final static Pattern PATTERN_RESOURCES_S_AP_ = - Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE); - - public final static String FN_ADB = - (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? - "adb.exe" : "adb"; //$NON-NLS-1$ //$NON-NLS-2$ - - public final static String FN_EMULATOR = - (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? - "emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$ - - public final static String FN_TRACEVIEW = - (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? - "traceview.exe" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$ - - /** Absolute path of the workspace root, i.e. "/" */ - public final static String WS_ROOT = WS_SEP; - - /** Absolute path of the resource folder, eg "/res".<br> This is a workspace path. */ - public final static String WS_RESOURCES = WS_SEP + SdkConstants.FD_RESOURCES; - - /** Absolute path of the resource folder, eg "/assets".<br> This is a workspace path. */ - public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS; - - /** Leaf of the javaDoc folder. Does not start with a separator. */ - public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/reference"; //$NON-NLS-1$ - - /** Path of the samples directory relative to the sdk folder. - * This is an OS path, ending with a separator. - * FIXME: remove once the NPW is fixed. */ - public final static String OS_SDK_SAMPLES_FOLDER = SdkConstants.FD_SAMPLES + File.separator; - - public final static String RE_DOT = "\\."; //$NON-NLS-1$ - /** Regexp for java extension, i.e. "\.java$" */ - public final static String RE_JAVA_EXT = "\\.java$"; //$NON-NLS-1$ - /** Regexp for aidl extension, i.e. "\.aidl$" */ - public final static String RE_AIDL_EXT = "\\.aidl$"; //$NON-NLS-1$ - - /** Namespace pattern for the custom resource XML, i.e. "http://schemas.android.com/apk/res/%s" */ - public final static String NS_CUSTOM_RESOURCES = "http://schemas.android.com/apk/res/%1$s"; //$NON-NLS-1$ - - /** The old common plug-in ID. Please do not use for new features. */ - public static final String COMMON_PLUGIN_ID = "com.android.ide.eclipse.common"; //$NON-NLS-1$ - - /** aapt marker error. */ - public final static String MARKER_AAPT = COMMON_PLUGIN_ID + ".aaptProblem"; //$NON-NLS-1$ - - /** XML marker error. */ - public final static String MARKER_XML = COMMON_PLUGIN_ID + ".xmlProblem"; //$NON-NLS-1$ - - /** aidl marker error. */ - public final static String MARKER_AIDL = COMMON_PLUGIN_ID + ".aidlProblem"; //$NON-NLS-1$ - - /** android marker error */ - public final static String MARKER_ANDROID = COMMON_PLUGIN_ID + ".androidProblem"; //$NON-NLS-1$ - - /** Name for the "type" marker attribute */ - public final static String MARKER_ATTR_TYPE = "android.type"; //$NON-NLS-1$ - /** Name for the "class" marker attribute */ - public final static String MARKER_ATTR_CLASS = "android.class"; //$NON-NLS-1$ - /** activity value for marker attribute "type" */ - public final static String MARKER_ATTR_TYPE_ACTIVITY = "activity"; //$NON-NLS-1$ - /** service value for marker attribute "type" */ - public final static String MARKER_ATTR_TYPE_SERVICE = "service"; //$NON-NLS-1$ - /** receiver value for marker attribute "type" */ - public final static String MARKER_ATTR_TYPE_RECEIVER = "receiver"; //$NON-NLS-1$ - /** provider value for marker attribute "type" */ - public final static String MARKER_ATTR_TYPE_PROVIDER = "provider"; //$NON-NLS-1$ - - public final static String CLASS_ACTIVITY = "android.app.Activity"; //$NON-NLS-1$ - public final static String CLASS_SERVICE = "android.app.Service"; //$NON-NLS-1$ - public final static String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$ - public final static String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$ - public final static String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$ - public final static String CLASS_BUNDLE = "android.os.Bundle"; //$NON-NLS-1$ - public final static String CLASS_R = "android.R"; //$NON-NLS-1$ - public final static String CLASS_MANIFEST_PERMISSION = "android.Manifest$permission"; //$NON-NLS-1$ - public final static String CLASS_INTENT = "android.content.Intent"; //$NON-NLS-1$ - public final static String CLASS_CONTEXT = "android.content.Context"; //$NON-NLS-1$ - public final static String CLASS_VIEW = "android.view.View"; //$NON-NLS-1$ - public final static String CLASS_VIEWGROUP = "android.view.ViewGroup"; //$NON-NLS-1$ - public final static String CLASS_LAYOUTPARAMS = "LayoutParams"; //$NON-NLS-1$ - public final static String CLASS_VIEWGROUP_LAYOUTPARAMS = - CLASS_VIEWGROUP + "$" + CLASS_LAYOUTPARAMS; //$NON-NLS-1$ - public final static String CLASS_FRAMELAYOUT = "FrameLayout"; //$NON-NLS-1$ - public final static String CLASS_PREFERENCE = "android.preference.Preference"; //$NON-NLS-1$ - public final static String CLASS_PREFERENCE_SCREEN = "PreferenceScreen"; //$NON-NLS-1$ - public final static String CLASS_PREFERENCES = - "android.preference." + CLASS_PREFERENCE_SCREEN; //$NON-NLS-1$ - public final static String CLASS_PREFERENCEGROUP = "android.preference.PreferenceGroup"; //$NON-NLS-1$ - public final static String CLASS_PARCELABLE = "android.os.Parcelable"; //$NON-NLS-1$ - - public final static String CLASS_BRIDGE = "com.android.layoutlib.bridge.Bridge"; //$NON-NLS-1$ - - /** - * Prefered compiler level, i.e. "1.5". - */ - public final static String COMPILER_COMPLIANCE_PREFERRED = "1.5"; //$NON-NLS-1$ - /** - * List of valid compiler level, i.e. "1.5" and "1.6" - */ - public final static String[] COMPILER_COMPLIANCE = { - "1.5", //$NON-NLS-1$ - "1.6", //$NON-NLS-1$ - }; - - /** The base URL where to find the Android class & manifest documentation */ - public static final String CODESITE_BASE_URL = "http://code.google.com/android"; //$NON-NLS-1$ - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/EclipseUiHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/EclipseUiHelper.java deleted file mode 100644 index 6dc8562..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/EclipseUiHelper.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2008 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.common; - -import org.eclipse.ui.IViewPart; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; - -/** - * Helpers for Eclipse UI related stuff. - */ -public final class EclipseUiHelper { - - /** View Id for the default Eclipse Content Outline view. */ - public static final String CONTENT_OUTLINE_VIEW_ID = "org.eclipse.ui.views.ContentOutline"; - /** View Id for the default Eclipse Property Sheet view. */ - public static final String PROPERTY_SHEET_VIEW_ID = "org.eclipse.ui.views.PropertySheet"; - - /** This class never gets instantiated. */ - private EclipseUiHelper() { - } - - /** - * Shows the corresponding view. - * <p/> - * Silently fails in case of error. - * - * @param viewId One of {@link #CONTENT_OUTLINE_VIEW_ID}, {@link #PROPERTY_SHEET_VIEW_ID}. - * @param activate True to force activate (i.e. takes focus), false to just make visible (i.e. - * does not steal focus.) - */ - public static void showView(String viewId, boolean activate) { - IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (win != null) { - IWorkbenchPage page = win.getActivePage(); - if (page != null) { - try { - IViewPart part = page.showView(viewId, - null /* secondaryId */, - activate ? IWorkbenchPage.VIEW_ACTIVATE : IWorkbenchPage.VIEW_VISIBLE); - } catch (PartInitException e) { - // ignore - } - } - } - - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/Messages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/Messages.java deleted file mode 100644 index 3f1bde4..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/Messages.java +++ /dev/null @@ -1,21 +0,0 @@ - -package com.android.ide.eclipse.common; - -import org.eclipse.osgi.util.NLS; - -public class Messages extends NLS { - private static final String BUNDLE_NAME = "com.android.ide.eclipse.common.messages"; //$NON-NLS-1$ - - public static String Console_Data_Project_Tag; - - public static String Console_Date_Tag; - - - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/SdkStatsHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/SdkStatsHelper.java deleted file mode 100644 index 345c663..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/SdkStatsHelper.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2008 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.common; - -import com.android.sdkstats.SdkStatsService; - -import org.osgi.framework.Version; - -/** - * Helper class to access the ping usage stat server. - */ -public class SdkStatsHelper { - - /** - * Pings the usage start server. - * @param pluginName the name of the plugin to appear in the stats - * @param pluginVersion the {@link Version} of the plugin. - */ - public static void pingUsageServer(String pluginName, Version pluginVersion) { - String versionString = String.format("%1$d.%2$d.%3$d", pluginVersion.getMajor(), - pluginVersion.getMinor(), pluginVersion.getMicro()); - - SdkStatsService.ping(pluginName, versionString); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/StreamHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/StreamHelper.java deleted file mode 100644 index 6ccf4f2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/StreamHelper.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2007 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.common; - -import org.eclipse.ui.console.MessageConsoleStream; - -import java.util.Calendar; - -/** - * Stream helper class. - */ -public class StreamHelper { - - /** - * Prints messages, associated with a project to the specified stream - * @param stream The stream to write to - * @param tag The tag associated to the message. Can be null - * @param objects The objects to print through their toString() method (or directly for - * {@link String} objects. - */ - public static synchronized void printToStream(MessageConsoleStream stream, String tag, - Object... objects) { - String dateTag = getMessageTag(tag); - - for (Object obj : objects) { - stream.print(dateTag); - if (obj instanceof String) { - stream.println((String)obj); - } else { - stream.println(obj.toString()); - } - } - } - - /** - * Creates a string containing the current date/time, and the tag - * @param tag The tag associated to the message. Can be null - * @return The dateTag - */ - public static String getMessageTag(String tag) { - Calendar c = Calendar.getInstance(); - - if (tag == null) { - return String.format(Messages.Console_Date_Tag, c); - } - - return String.format(Messages.Console_Data_Project_Tag, c, tag); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/messages.properties deleted file mode 100644 index dba6edc..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/messages.properties +++ /dev/null @@ -1,2 +0,0 @@ -Console_Date_Tag=[%1$tF %1$tT] -Console_Data_Project_Tag=[%1$tF %1$tT - %2$s] diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/preferences/UsagePreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/preferences/UsagePreferencePage.java deleted file mode 100644 index 58c2f40..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/preferences/UsagePreferencePage.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2008 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.common.preferences; - -import com.android.sdkstats.SdkStatsService; - -import org.eclipse.jface.preference.BooleanFieldEditor; -import org.eclipse.jface.preference.PreferencePage; -import org.eclipse.jface.preference.PreferenceStore; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Link; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPreferencePage; - -import java.io.IOException; - -public class UsagePreferencePage extends PreferencePage implements IWorkbenchPreferencePage { - - private BooleanFieldEditor mOptInCheckBox; - - public UsagePreferencePage() { - } - - public void init(IWorkbench workbench) { - // pass - } - - @Override - protected Control createContents(Composite parent) { - Composite top = new Composite(parent, SWT.NONE); - top.setLayout(new GridLayout(1, false)); - top.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - Link text = new Link(top, SWT.WRAP); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.widthHint = 200; - text.setLayoutData(gd); - text.setText(SdkStatsService.BODY_TEXT); - - text.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - SdkStatsService.openUrl(event.text); - } - }); - - mOptInCheckBox = new BooleanFieldEditor(SdkStatsService.PING_OPT_IN, - SdkStatsService.CHECKBOX_TEXT, top); - mOptInCheckBox.setPage(this); - mOptInCheckBox.setPreferenceStore(SdkStatsService.getPreferenceStore()); - mOptInCheckBox.load(); - - return top; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.preference.PreferencePage#performCancel() - */ - @Override - public boolean performCancel() { - mOptInCheckBox.load(); - return super.performCancel(); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.preference.PreferencePage#performDefaults() - */ - @Override - protected void performDefaults() { - mOptInCheckBox.loadDefault(); - super.performDefaults(); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.preference.PreferencePage#performOk() - */ - @Override - public boolean performOk() { - save(); - return super.performOk(); - } - - /* (non-Javadoc) - * @see org.eclipse.jface.preference.PreferencePage#performApply() - */ - @Override - protected void performApply() { - save(); - super.performApply(); - } - - private void save() { - try { - PreferenceStore store = SdkStatsService.getPreferenceStore(); - if (store != null) { - store.setValue(SdkStatsService.PING_OPT_IN, mOptInCheckBox.getBooleanValue()); - store.save(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java deleted file mode 100644 index cd238d2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2007 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.common.project; - -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.xml.sax.InputSource; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; - -/** - * Utility class that manages the AndroidManifest.xml file. - * <p/> - * All the get method work by XPath. Repeated calls to those may warrant using - * {@link AndroidManifestParser} instead. - */ -public class AndroidManifestHelper { - private IFile mManifestIFile; - private File mManifestFile; - private XPath mXPath; - - /** - * Creates an AndroidManifest based on an existing Eclipse {@link IProject} object. - * </p> - * Use {@link #exists()} to check if the manifest file really exists in the project. - * - * @param project The project to search for the manifest. - */ - public AndroidManifestHelper(IProject project) { - mXPath = AndroidXPathFactory.newXPath(); - mManifestIFile = getManifest(project); - } - - /** - * Creates an AndroidManifest based on a file path. - * <p/> - * Use {@link #exists()} to check if the manifest file really exists. - * - * @param osManifestFilePath the os path to the AndroidManifest.xml file. - */ - public AndroidManifestHelper(String osManifestFilePath) { - mXPath = AndroidXPathFactory.newXPath(); - mManifestFile = new File(osManifestFilePath); - } - - - /** - * Returns the underlying {@link IFile} for the android manifest XML file, if found in the - * given Eclipse project. - * - * Always return null if the constructor that takes an {@link IProject} was NOT called. - * - * @return The IFile for the androidManifest.xml or null if no such file could be found. - */ - public IFile getManifestIFile() { - return mManifestIFile; - } - - /** - * Returns the underlying {@link File} for the android manifest XML file. - */ - public File getManifestFile() { - if (mManifestIFile != null) { - return mManifestIFile.getLocation().toFile(); - } - - return mManifestFile; - } - - /** - * Returns the package name defined in the manifest file. - * - * @return A String object with the package or null if any error happened. - */ - public String getPackageName() { - try { - return mXPath.evaluate("/manifest/@package", getSource()); //$NON-NLS-1$ - } catch (XPathExpressionException e1) { - // If the XPath failed to evaluate, we'll return null. - } catch (Exception e) { - // if this happens this is due to the resource being out of sync. - // so we must refresh it and do it again - - // for any other kind of exception we must return null as well; - } - - return null; - } - - /** - * Returns the minSdkVersion defined in the manifest file. - * - * @return A String object with the package or null if any error happened. - */ - public String getMinSdkVersion() { - try { - return mXPath.evaluate("/manifest/uses-sdk/@" //$NON-NLS-1$ - + AndroidXPathFactory.DEFAULT_NS_PREFIX - + ":minSdkVersion", getSource()); //$NON-NLS-1$ - } catch (XPathExpressionException e1) { - // If the XPath failed to evaluate, we'll return null. - } catch (Exception e) { - // if this happens this is due to the resource being out of sync. - // so we must refresh it and do it again - - // for any other kind of exception we must return null as well; - } - - return null; - } - /** - * Returns the i-th activity defined in the manifest file. - * - * @param index The 1-based index of the activity to return. - * @return A String object with the activity or null if any error happened. - */ - public String getActivityName(int index) { - try { - return mXPath.evaluate("/manifest/application/activity[" //$NON-NLS-1$ - + index - + "]/@" //$NON-NLS-1$ - + AndroidXPathFactory.DEFAULT_NS_PREFIX +":name", //$NON-NLS-1$ - getSource()); - } catch (XPathExpressionException e1) { - // If the XPath failed to evaluate, we'll return null. - } catch (Exception e) { - // if this happens this is due to the resource being out of sync. - // so we must refresh it and do it again - - // for any other kind of exception we must return null as well; - } - return null; - } - - /** - * Returns an IFile object representing the manifest for the specified - * project. - * - * @param project The project containing the manifest file. - * @return An IFile object pointing to the manifest or null if the manifest - * is missing. - */ - public static IFile getManifest(IProject project) { - IResource r = project.findMember(AndroidConstants.WS_SEP - + AndroidConstants.FN_ANDROID_MANIFEST); - - if (r == null || r.exists() == false || (r instanceof IFile) == false) { - return null; - } - return (IFile) r; - } - - /** - * Combines a java package, with a class value from the manifest to make a fully qualified - * class name - * @param javaPackage the java package from the manifest. - * @param className the class name from the manifest. - * @return the fully qualified class name. - */ - public static String combinePackageAndClassName(String javaPackage, String className) { - if (className == null || className.length() == 0) { - return javaPackage; - } - if (javaPackage == null || javaPackage.length() == 0) { - return className; - } - - // the class name can be a subpackage (starts with a '.' - // char), a simple class name (no dot), or a full java package - boolean startWithDot = (className.charAt(0) == '.'); - boolean hasDot = (className.indexOf('.') != -1); - if (startWithDot || hasDot == false) { - - // add the concatenation of the package and class name - if (startWithDot) { - return javaPackage + className; - } else { - return javaPackage + '.' + className; - } - } else { - // just add the class as it should be a fully qualified java name. - return className; - } - } - - - - /** - * Returns true either if an androidManifest.xml file was found in the project - * or if the given file path exists. - */ - public boolean exists() { - if (mManifestIFile != null) { - return mManifestIFile.exists(); - } else if (mManifestFile != null) { - return mManifestFile.exists(); - } - - return false; - } - - /** - * Returns an InputSource for XPath. - * - * @throws FileNotFoundException if file does not exist. - * @throws CoreException if the {@link IFile} does not exist. - */ - private InputSource getSource() throws FileNotFoundException, CoreException { - if (mManifestIFile != null) { - return new InputSource(mManifestIFile.getContents()); - } else if (mManifestFile != null) { - return new InputSource(new FileReader(mManifestFile)); - } - - return null; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java deleted file mode 100644 index 850c59d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Copyright (C) 2007 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.common.project; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IJavaProject; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Set; -import java.util.TreeSet; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -public class AndroidManifestParser { - - private final static String ATTRIBUTE_PACKAGE = "package"; //$NON-NLS-1$ - private final static String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$ - private final static String ATTRIBUTE_PROCESS = "process"; //$NON-NLS-$ - private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$ - private final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$ - private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$ - private final static String NODE_APPLICATION = "application"; //$NON-NLS-1$ - private final static String NODE_ACTIVITY = "activity"; //$NON-NLS-1$ - private final static String NODE_SERVICE = "service"; //$NON-NLS-1$ - private final static String NODE_RECEIVER = "receiver"; //$NON-NLS-1$ - private final static String NODE_PROVIDER = "provider"; //$NON-NLS-1$ - private final static String NODE_INTENT = "intent-filter"; //$NON-NLS-1$ - private final static String NODE_ACTION = "action"; //$NON-NLS-1$ - private final static String NODE_CATEGORY = "category"; //$NON-NLS-1$ - private final static String NODE_USES_SDK = "uses-sdk"; //$NON-NLS-1$ - - private final static int LEVEL_MANIFEST = 0; - private final static int LEVEL_APPLICATION = 1; - private final static int LEVEL_ACTIVITY = 2; - private final static int LEVEL_INTENT_FILTER = 3; - private final static int LEVEL_CATEGORY = 4; - - private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$ - private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$ - - private static class ManifestHandler extends XmlErrorHandler { - - //--- data read from the parsing - - /** Application package */ - private String mPackage; - /** List of all activities */ - private final ArrayList<String> mActivities = new ArrayList<String>(); - /** Launcher activity */ - private String mLauncherActivity = null; - /** list of process names declared by the manifest */ - private Set<String> mProcesses = null; - /** debuggable attribute value. If null, the attribute is not present. */ - private Boolean mDebuggable = null; - /** API level requirement. if 0 the attribute was not present. */ - private int mApiLevelRequirement = 0; - - //--- temporary data/flags used during parsing - private IJavaProject mJavaProject; - private boolean mGatherData = false; - private boolean mMarkErrors = false; - private int mCurrentLevel = 0; - private int mValidLevel = 0; - private boolean mFoundMainAction = false; - private boolean mFoundLauncherCategory = false; - private String mCurrentActivity = null; - private Locator mLocator; - - /** - * - * @param manifestFile - * @param errorListener - * @param gatherData - * @param javaProject - * @param markErrors - */ - ManifestHandler(IFile manifestFile, XmlErrorListener errorListener, - boolean gatherData, IJavaProject javaProject, boolean markErrors) { - super(manifestFile, errorListener); - mGatherData = gatherData; - mJavaProject = javaProject; - mMarkErrors = markErrors; - } - - /** - * Returns the package defined in the manifest, if found. - * @return The package name or null if not found. - */ - String getPackage() { - return mPackage; - } - - /** - * Returns the list of activities found in the manifest. - * @return An array of fully qualified class names, or empty if no activity were found. - */ - String[] getActivities() { - return mActivities.toArray(new String[mActivities.size()]); - } - - /** - * Returns the name of one activity found in the manifest, that is configured to show - * up in the HOME screen. - * @return the fully qualified name of a HOME activity or null if none were found. - */ - String getLauncherActivity() { - return mLauncherActivity; - } - - /** - * Returns the list of process names declared by the manifest. - */ - String[] getProcesses() { - if (mProcesses != null) { - return mProcesses.toArray(new String[mProcesses.size()]); - } - - return new String[0]; - } - - /** - * Returns the <code>debuggable</code> attribute value or null if it is not set. - */ - Boolean getDebuggable() { - return mDebuggable; - } - - /** - * Returns the <code>minSdkVersion</code> attribute, or 0 if it's not set. - */ - int getApiLevelRequirement() { - return mApiLevelRequirement; - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator) - */ - @Override - public void setDocumentLocator(Locator locator) { - mLocator = locator; - super.setDocumentLocator(locator); - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, - * java.lang.String, org.xml.sax.Attributes) - */ - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) - throws SAXException { - try { - if (mGatherData == false) { - return; - } - - // if we're at a valid level - if (mValidLevel == mCurrentLevel) { - String value; - switch (mValidLevel) { - case LEVEL_MANIFEST: - if (NODE_MANIFEST.equals(localName)) { - // lets get the package name. - mPackage = getAttributeValue(attributes, ATTRIBUTE_PACKAGE, - false /* hasNamespace */); - mValidLevel++; - } - break; - case LEVEL_APPLICATION: - if (NODE_APPLICATION.equals(localName)) { - value = getAttributeValue(attributes, ATTRIBUTE_PROCESS, - true /* hasNamespace */); - if (value != null) { - addProcessName(value); - } - - value = getAttributeValue(attributes, ATTRIBUTE_DEBUGGABLE, - true /* hasNamespace*/); - if (value != null) { - mDebuggable = Boolean.parseBoolean(value); - } - - mValidLevel++; - } else if (NODE_USES_SDK.equals(localName)) { - value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION, - true /* hasNamespace */); - - try { - mApiLevelRequirement = Integer.parseInt(value); - } catch (NumberFormatException e) { - handleError(e, -1 /* lineNumber */); - } - } - break; - case LEVEL_ACTIVITY: - if (NODE_ACTIVITY.equals(localName)) { - processActivityNode(attributes); - mValidLevel++; - } else if (NODE_SERVICE.equals(localName)) { - processNode(attributes, AndroidConstants.CLASS_SERVICE); - mValidLevel++; - } else if (NODE_RECEIVER.equals(localName)) { - processNode(attributes, AndroidConstants.CLASS_BROADCASTRECEIVER); - mValidLevel++; - } else if (NODE_PROVIDER.equals(localName)) { - processNode(attributes, AndroidConstants.CLASS_CONTENTPROVIDER); - mValidLevel++; - } - break; - case LEVEL_INTENT_FILTER: - // only process this level if we are in an activity - if (mCurrentActivity != null && NODE_INTENT.equals(localName)) { - // if we're at the intent level, lets reset some flag to - // be used when parsing the children - mFoundMainAction = false; - mFoundLauncherCategory = false; - mValidLevel++; - } - break; - case LEVEL_CATEGORY: - if (mCurrentActivity != null && mLauncherActivity == null) { - if (NODE_ACTION.equals(localName)) { - // get the name attribute - if (ACTION_MAIN.equals( - getAttributeValue(attributes, ATTRIBUTE_NAME, - true /* hasNamespace */))) { - mFoundMainAction = true; - } - } else if (NODE_CATEGORY.equals(localName)) { - if (CATEGORY_LAUNCHER.equals( - getAttributeValue(attributes, ATTRIBUTE_NAME, - true /* hasNamespace */))) { - mFoundLauncherCategory = true; - } - } - - // no need to increase mValidLevel as we don't process anything - // below this level. - } - break; - } - } - - mCurrentLevel++; - } finally { - super.startElement(uri, localName, name, attributes); - } - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, - * java.lang.String) - */ - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - try { - if (mGatherData == false) { - return; - } - - // decrement the levels. - if (mValidLevel == mCurrentLevel) { - mValidLevel--; - } - mCurrentLevel--; - - // if we're at a valid level - // process the end of the element - if (mValidLevel == mCurrentLevel) { - switch (mValidLevel) { - case LEVEL_ACTIVITY: - mCurrentActivity = null; - break; - case LEVEL_INTENT_FILTER: - // if we found both a main action and a launcher category, this is our - // launcher activity! - if (mCurrentActivity != null && - mFoundMainAction && mFoundLauncherCategory) { - mLauncherActivity = mCurrentActivity; - } - break; - default: - break; - } - - } - } finally { - super.endElement(uri, localName, name); - } - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException) - */ - @Override - public void error(SAXParseException e) { - if (mMarkErrors) { - handleError(e, e.getLineNumber()); - } - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException) - */ - @Override - public void fatalError(SAXParseException e) { - if (mMarkErrors) { - handleError(e, e.getLineNumber()); - } - } - - /* (non-Javadoc) - * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException) - */ - @Override - public void warning(SAXParseException e) throws SAXException { - if (mMarkErrors) { - super.warning(e); - } - } - - /** - * Processes the activity node. - * @param attributes the attributes for the activity node. - */ - private void processActivityNode(Attributes attributes) { - // lets get the activity name, and add it to the list - String activityName = getAttributeValue(attributes, ATTRIBUTE_NAME, - true /* hasNamespace */); - if (activityName != null) { - mCurrentActivity = AndroidManifestHelper.combinePackageAndClassName(mPackage, - activityName); - mActivities.add(mCurrentActivity); - - if (mMarkErrors) { - checkClass(mCurrentActivity, AndroidConstants.CLASS_ACTIVITY, - true /* testVisibility */); - } - } else { - // no activity found! Aapt will output an error, - // so we don't have to do anything - mCurrentActivity = activityName; - } - - String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS, - true /* hasNamespace */); - if (processName != null) { - addProcessName(processName); - } - } - - /** - * Processes the service/receiver/provider nodes. - * @param attributes the attributes for the activity node. - * @param superClassName the fully qualified name of the super class that this - * node is representing - */ - private void processNode(Attributes attributes, String superClassName) { - // lets get the class name, and check it if required. - String serviceName = getAttributeValue(attributes, ATTRIBUTE_NAME, - true /* hasNamespace */); - if (serviceName != null) { - serviceName = AndroidManifestHelper.combinePackageAndClassName(mPackage, - serviceName); - - if (mMarkErrors) { - checkClass(serviceName, superClassName, false /* testVisibility */); - } - } - - String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS, - true /* hasNamespace */); - if (processName != null) { - addProcessName(processName); - } - } - - /** - * Checks that a class is valid and can be used in the Android Manifest. - * <p/> - * Errors are put as {@link IMarker} on the manifest file. - * @param className the fully qualified name of the class to test. - * @param superClassName the fully qualified name of the class it is supposed to extend. - * @param testVisibility if <code>true</code>, the method will check the visibility of - * the class or of its constructors. - */ - private void checkClass(String className, String superClassName, boolean testVisibility) { - // we need to check the validity of the activity. - String result = BaseProjectHelper.testClassForManifest(mJavaProject, - className, superClassName, testVisibility); - if (result != BaseProjectHelper.TEST_CLASS_OK) { - // get the line number - int line = mLocator.getLineNumber(); - - // mark the file - IMarker marker = BaseProjectHelper.addMarker(getFile(), - AndroidConstants.MARKER_ANDROID, - result, line, IMarker.SEVERITY_ERROR); - - // add custom attributes to be used by the manifest editor. - if (marker != null) { - try { - marker.setAttribute(AndroidConstants.MARKER_ATTR_TYPE, - AndroidConstants.MARKER_ATTR_TYPE_ACTIVITY); - marker.setAttribute(AndroidConstants.MARKER_ATTR_CLASS, className); - } catch (CoreException e) { - } - } - } - - } - - /** - * Searches through the attributes list for a particular one and returns its value. - * @param attributes the attribute list to search through - * @param attributeName the name of the attribute to look for. - * @param hasNamespace Indicates whether the attribute has an android namespace. - * @return a String with the value or null if the attribute was not found. - * @see SdkConstants#NS_RESOURCES - */ - private String getAttributeValue(Attributes attributes, String attributeName, - boolean hasNamespace) { - int count = attributes.getLength(); - for (int i = 0 ; i < count ; i++) { - if (attributeName.equals(attributes.getLocalName(i)) && - ((hasNamespace && - SdkConstants.NS_RESOURCES.equals(attributes.getURI(i))) || - (hasNamespace == false && attributes.getURI(i).length() == 0))) { - return attributes.getValue(i); - } - } - - return null; - } - - private void addProcessName(String processName) { - if (mProcesses == null) { - mProcesses = new TreeSet<String>(); - } - - mProcesses.add(processName); - } - } - - private static SAXParserFactory sParserFactory; - - private final String mJavaPackage; - private final String[] mActivities; - private final String mLauncherActivity; - private final String[] mProcesses; - private final Boolean mDebuggable; - private final int mApiLevelRequirement; - - static { - sParserFactory = SAXParserFactory.newInstance(); - sParserFactory.setNamespaceAware(true); - } - - /** - * Parses the Android Manifest, and returns an object containing - * the result of the parsing. - * @param javaProject The java project. - * @param manifestFile the {@link IFile} representing the manifest file. - * @param errorListener - * @param gatherData indicates whether the parsing will extract data from the manifest. - * @param markErrors indicates whether the error found during parsing should put a - * marker on the file. For class validation errors to put a marker, <code>gatherData</code> - * must be set to <code>true</code> - * @return an {@link AndroidManifestParser} or null if the parsing failed. - * @throws CoreException - */ - public static AndroidManifestParser parse(IJavaProject javaProject, IFile manifestFile, - XmlErrorListener errorListener, boolean gatherData, boolean markErrors) - throws CoreException { - try { - SAXParser parser = sParserFactory.newSAXParser(); - - ManifestHandler manifestHandler = new ManifestHandler(manifestFile, - errorListener, gatherData, javaProject, markErrors); - - parser.parse(new InputSource(manifestFile.getContents()), manifestHandler); - - // get the result from the handler - - return new AndroidManifestParser(manifestHandler.getPackage(), - manifestHandler.getActivities(), manifestHandler.getLauncherActivity(), - manifestHandler.getProcesses(), manifestHandler.getDebuggable(), - manifestHandler.getApiLevelRequirement()); - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (IOException e) { - } finally { - } - - return null; - } - - /** - * Parses the Android Manifest for the specified project, and returns an object containing - * the result of the parsing. - * @param javaProject The java project. Required if <var>markErrors</var> is <code>true</code> - * @param errorListener the {@link XmlErrorListener} object being notified of the presence - * of errors. Optional. - * @param gatherData indicates whether the parsing will extract data from the manifest. - * @param markErrors indicates whether the error found during parsing should put a - * marker on the file. For class validation errors to put a marker, <code>gatherData</code> - * must be set to <code>true</code> - * @return an {@link AndroidManifestParser} or null if the parsing failed. - * @throws CoreException - */ - public static AndroidManifestParser parse(IJavaProject javaProject, - XmlErrorListener errorListener, boolean gatherData, boolean markErrors) - throws CoreException { - try { - SAXParser parser = sParserFactory.newSAXParser(); - - IFile manifestFile = AndroidManifestHelper.getManifest(javaProject.getProject()); - if (manifestFile != null) { - ManifestHandler manifestHandler = new ManifestHandler(manifestFile, - errorListener, gatherData, javaProject, markErrors); - - parser.parse(new InputSource(manifestFile.getContents()), manifestHandler); - - // get the result from the handler - return new AndroidManifestParser(manifestHandler.getPackage(), - manifestHandler.getActivities(), manifestHandler.getLauncherActivity(), - manifestHandler.getProcesses(), manifestHandler.getDebuggable(), - manifestHandler.getApiLevelRequirement()); - } - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (IOException e) { - } finally { - } - - return null; - } - - /** - * Parses the manifest file, collects data, and checks for errors. - * @param javaProject The java project. Required. - * @param manifestFile The manifest file to parse. - * @param errorListener the {@link XmlErrorListener} object being notified of the presence - * of errors. Optional. - * @return an {@link AndroidManifestParser} or null if the parsing failed. - * @throws CoreException - */ - public static AndroidManifestParser parseForError(IJavaProject javaProject, IFile manifestFile, - XmlErrorListener errorListener) throws CoreException { - return parse(javaProject, manifestFile, errorListener, true, true); - } - - /** - * Parses the manifest file, and collects data. - * @param manifestFile The manifest file to parse. - * @return an {@link AndroidManifestParser} or null if the parsing failed. - * @throws CoreException - */ - public static AndroidManifestParser parseForData(IFile manifestFile) throws CoreException { - return parse(null /* javaProject */, manifestFile, null /* errorListener */, - true /* gatherData */, false /* markErrors */); - } - - /** - * Returns the package defined in the manifest, if found. - * @return The package name or null if not found. - */ - public String getPackage() { - return mJavaPackage; - } - - /** - * Returns the list of activities found in the manifest. - * @return An array of fully qualified class names, or empty if no activity were found. - */ - public String[] getActivities() { - return mActivities; - } - - /** - * Returns the name of one activity found in the manifest, that is configured to show - * up in the HOME screen. - * @return the fully qualified name of a HOME activity or null if none were found. - */ - public String getLauncherActivity() { - return mLauncherActivity; - } - - /** - * Returns the list of process names declared by the manifest. - */ - public String[] getProcesses() { - return mProcesses; - } - - /** - * Returns the debuggable attribute value or <code>null</code> if it is not set. - */ - public Boolean getDebuggable() { - return mDebuggable; - } - - /** - * Returns the <code>minSdkVersion</code> attribute, or 0 if it's not set. - */ - public int getApiLevelRequirement() { - return mApiLevelRequirement; - } - - - /** - * Private constructor to enforce using - * {@link #parse(IJavaProject, XmlErrorListener, boolean, boolean)}, - * {@link #parse(IJavaProject, IFile, XmlErrorListener, boolean, boolean)}, - * or {@link #parseForError(IJavaProject, IFile, XmlErrorListener)} to get an - * {@link AndroidManifestParser} object. - * @param javaPackage the package parsed from the manifest. - * @param activities the list of activities parsed from the manifest. - * @param launcherActivity the launcher activity parser from the manifest. - * @param processes the list of custom processes declared in the manifest. - * @param debuggable the debuggable attribute, or null if not set. - * @param apiLevelRequirement the minSdkVersion attribute value or 0 if not set. - */ - private AndroidManifestParser(String javaPackage, String[] activities, - String launcherActivity, String[] processes, Boolean debuggable, - int apiLevelRequirement) { - mJavaPackage = javaPackage; - mActivities = activities; - mLauncherActivity = launcherActivity; - mProcesses = processes; - mDebuggable = debuggable; - mApiLevelRequirement = apiLevelRequirement; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java deleted file mode 100644 index 0f1e255..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2007 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.common.project; - -import com.android.sdklib.SdkConstants; - -import java.util.Iterator; - -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathFactory; - -/** - * XPath factory with automatic support for the android namespace. - */ -public class AndroidXPathFactory { - public final static String DEFAULT_NS_PREFIX = "android"; //$NON-NLS-1$ - - private final static XPathFactory sFactory = XPathFactory.newInstance(); - - /** Namespace context for Android resource XML files. */ - private static class AndroidNamespaceContext implements NamespaceContext { - private String mAndroidPrefix; - - /** - * Construct the context with the prefix associated with the android namespace. - * @param androidPrefix the Prefix - */ - public AndroidNamespaceContext(String androidPrefix) { - mAndroidPrefix = androidPrefix; - } - - public String getNamespaceURI(String prefix) { - if (prefix != null) { - if (prefix.equals(mAndroidPrefix)) { - return SdkConstants.NS_RESOURCES; - } - } - - return XMLConstants.NULL_NS_URI; - } - - public String getPrefix(String namespaceURI) { - // This isn't necessary for our use. - assert false; - return null; - } - - public Iterator<?> getPrefixes(String namespaceURI) { - // This isn't necessary for our use. - assert false; - return null; - } - } - - /** - * Creates a new XPath object, specifying which prefix in the query is used for the - * android namespace. - * @param androidPrefix The namespace prefix. - */ - public static XPath newXPath(String androidPrefix) { - XPath xpath = sFactory.newXPath(); - xpath.setNamespaceContext(new AndroidNamespaceContext(androidPrefix)); - return xpath; - } - - /** - * Creates a new XPath object using the default prefix for the android namespace. - * @see #DEFAULT_NS_PREFIX - */ - public static XPath newXPath() { - return newXPath(DEFAULT_NS_PREFIX); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java deleted file mode 100644 index bd8b444..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (C) 2007 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.common.project; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.XmlErrorHandler.XmlErrorListener; - -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.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.Flags; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IMethod; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jdt.ui.actions.OpenJavaPerspectiveAction; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.texteditor.IDocumentProvider; -import org.eclipse.ui.texteditor.ITextEditor; - -import java.util.ArrayList; - -/** - * Utility methods to manipulate projects. - */ -public final class BaseProjectHelper { - - public static final String TEST_CLASS_OK = null; - - /** - * returns a list of source classpath for a specified project - * @param javaProject - * @return a list of path relative to the workspace root. - */ - public static ArrayList<IPath> getSourceClasspaths(IJavaProject javaProject) { - ArrayList<IPath> sourceList = new ArrayList<IPath>(); - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - if (e.getEntryKind() == IClasspathEntry.CPE_SOURCE) { - sourceList.add(e.getPath()); - } - } - } - return sourceList; - } - - /** - * Adds a marker to a file on a specific line. This methods catches thrown - * {@link CoreException}, and returns null instead. - * @param file the file to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param lineNumber the line number where to put the mark. If line is < 1, it puts the marker - * on line 1. - * @param severity the severity of the marker. - * @return the IMarker that was added or null if it failed to add one. - */ - public final static IMarker addMarker(IResource file, String markerId, - String message, int lineNumber, int severity) { - try { - IMarker marker = file.createMarker(markerId); - marker.setAttribute(IMarker.MESSAGE, message); - marker.setAttribute(IMarker.SEVERITY, severity); - if (lineNumber < 1) { - lineNumber = 1; - } - marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); - - // on Windows, when adding a marker to a project, it takes a refresh for the marker - // to show. In order to fix this we're forcing a refresh of elements receiving - // markers (and only the element, not its children), to force the marker display. - file.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); - - return marker; - } catch (CoreException e) { - AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'", //$NON-NLS-1$ - markerId, file.getFullPath()); - } - - return null; - } - - /** - * Adds a marker to a resource. This methods catches thrown {@link CoreException}, - * and returns null instead. - * @param resource the file to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param severity the severity of the marker. - * @return the IMarker that was added or null if it failed to add one. - */ - public final static IMarker addMarker(IResource resource, String markerId, - String message, int severity) { - try { - IMarker marker = resource.createMarker(markerId); - marker.setAttribute(IMarker.MESSAGE, message); - marker.setAttribute(IMarker.SEVERITY, severity); - - // on Windows, when adding a marker to a project, it takes a refresh for the marker - // to show. In order to fix this we're forcing a refresh of elements receiving - // markers (and only the element, not its children), to force the marker display. - resource.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); - - return marker; - } catch (CoreException e) { - AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'", //$NON-NLS-1$ - markerId, resource.getFullPath()); - } - - return null; - } - - /** - * Adds a marker to a resource. This method does not catch {@link CoreException} and instead - * throw them. - * @param resource the file to be marked - * @param markerId The id of the marker to add. - * @param message the message associated with the mark - * @param lineNumber the line number where to put the mark if != -1. - * @param severity the severity of the marker. - * @param priority the priority of the marker - * @return the IMarker that was added. - * @throws CoreException - */ - public final static IMarker addMarker(IResource resource, String markerId, - String message, int lineNumber, int severity, int priority) throws CoreException { - IMarker marker = resource.createMarker(markerId); - marker.setAttribute(IMarker.MESSAGE, message); - marker.setAttribute(IMarker.SEVERITY, severity); - if (lineNumber != -1) { - marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); - } - marker.setAttribute(IMarker.PRIORITY, priority); - - // on Windows, when adding a marker to a project, it takes a refresh for the marker - // to show. In order to fix this we're forcing a refresh of elements receiving - // markers (and only the element, not its children), to force the marker display. - resource.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); - - return marker; - } - - /** - * Tests that a class name is valid for usage in the manifest. - * <p/> - * This tests the class existence, that it can be instantiated (ie it must not be abstract, - * nor non static if enclosed), and that it extends the proper super class (not necessarily - * directly) - * @param javaProject the {@link IJavaProject} containing the class. - * @param className the fully qualified name of the class to test. - * @param superClassName the fully qualified name of the expected super class. - * @param testVisibility if <code>true</code>, the method will check the visibility of the class - * or of its constructors. - * @return {@link #TEST_CLASS_OK} or an error message. - */ - public final static String testClassForManifest(IJavaProject javaProject, String className, - String superClassName, boolean testVisibility) { - try { - // replace $ by . - String javaClassName = className.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ - - // look for the IType object for this class - IType type = javaProject.findType(javaClassName); - if (type != null && type.exists()) { - // test that the class is not abstract - int flags = type.getFlags(); - if (Flags.isAbstract(flags)) { - return String.format("%1$s is abstract", className); - } - - // test whether the class is public or not. - if (testVisibility && Flags.isPublic(flags) == false) { - // if its not public, it may have a public default constructor, - // which would then be fine. - IMethod basicConstructor = type.getMethod(type.getElementName(), new String[0]); - if (basicConstructor != null && basicConstructor.exists()) { - int constructFlags = basicConstructor.getFlags(); - if (Flags.isPublic(constructFlags) == false) { - return String.format( - "%1$s or its default constructor must be public for the system to be able to instantiate it", - className); - } - } else { - return String.format( - "%1$s must be public, or the system will not be able to instantiate it.", - className); - } - } - - // If it's enclosed, test that it's static. If its declaring class is enclosed - // as well, test that it is also static, and public. - IType declaringType = type; - do { - IType tmpType = declaringType.getDeclaringType(); - if (tmpType != null) { - if (tmpType.exists()) { - flags = declaringType.getFlags(); - if (Flags.isStatic(flags) == false) { - return String.format("%1$s is enclosed, but not static", - declaringType.getFullyQualifiedName()); - } - - flags = tmpType.getFlags(); - if (testVisibility && Flags.isPublic(flags) == false) { - return String.format("%1$s is not public", - tmpType.getFullyQualifiedName()); - } - } else { - // if it doesn't exist, we need to exit so we may as well mark it null. - tmpType = null; - } - } - declaringType = tmpType; - } while (declaringType != null); - - // test the class inherit from the specified super class. - // get the type hierarchy - ITypeHierarchy hierarchy = type.newSupertypeHierarchy(new NullProgressMonitor()); - - // if the super class is not the reference class, it may inherit from - // it so we get its supertype. At some point it will be null and we - // will stop - IType superType = type; - boolean foundProperSuperClass = false; - while ((superType = hierarchy.getSuperclass(superType)) != null && - superType.exists()) { - if (superClassName.equals(superType.getFullyQualifiedName())) { - foundProperSuperClass = true; - } - } - - // didn't find the proper superclass? return false. - if (foundProperSuperClass == false) { - return String.format("%1$s does not extend %2$s", className, superClassName); - } - - return TEST_CLASS_OK; - } else { - return String.format("Class %1$s does not exist", className); - } - } catch (JavaModelException e) { - return String.format("%1$s: %2$s", className, e.getMessage()); - } - } - - /** - * Parses the manifest file for errors. - * <p/> - * This starts by removing the current XML marker, and then parses the xml for errors, both - * of XML type and of Android type (checking validity of class files). - * @param manifestFile - * @param errorListener - * @throws CoreException - */ - public static AndroidManifestParser parseManifestForError(IFile manifestFile, - XmlErrorListener errorListener) throws CoreException { - // remove previous markers - if (manifestFile.exists()) { - manifestFile.deleteMarkers(AndroidConstants.MARKER_XML, true, IResource.DEPTH_ZERO); - manifestFile.deleteMarkers(AndroidConstants.MARKER_ANDROID, true, IResource.DEPTH_ZERO); - } - - // and parse - return AndroidManifestParser.parseForError( - BaseProjectHelper.getJavaProject(manifestFile.getProject()), - manifestFile, errorListener); - } - - /** - * Returns the {@link IJavaProject} for a {@link IProject} object. - * <p/> - * This checks if the project has the Java Nature first. - * @param project - * @return the IJavaProject or null if the project couldn't be created or if the project - * does not have the Java Nature. - * @throws CoreException - */ - public static IJavaProject getJavaProject(IProject project) throws CoreException { - if (project != null && project.hasNature(JavaCore.NATURE_ID)) { - return JavaCore.create(project); - } - return null; - } - - /** - * Reveals a specific line in the source file defining a specified class, - * for a specific project. - * @param project - * @param className - * @param line - */ - public static void revealSource(IProject project, String className, int line) { - // in case the type is enclosed, we need to replace the $ with . - className = className.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS2$ - - // get the java project - IJavaProject javaProject = JavaCore.create(project); - - try { - // look for the IType matching the class name. - IType result = javaProject.findType(className); - if (result != null && result.exists()) { - // before we show the type in an editor window, we make sure the current - // workbench page has an editor area (typically the ddms perspective doesn't). - IWorkbench workbench = PlatformUI.getWorkbench(); - IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); - IWorkbenchPage page = window.getActivePage(); - if (page.isEditorAreaVisible() == false) { - // no editor area? we open the java perspective. - new OpenJavaPerspectiveAction().run(); - } - - IEditorPart editor = JavaUI.openInEditor(result); - if (editor instanceof ITextEditor) { - // get the text editor that was just opened. - ITextEditor textEditor = (ITextEditor)editor; - - IEditorInput input = textEditor.getEditorInput(); - - // get the location of the line to show. - IDocumentProvider documentProvider = textEditor.getDocumentProvider(); - IDocument document = documentProvider.getDocument(input); - IRegion lineInfo = document.getLineInformation(line - 1); - - // select and reveal the line. - textEditor.selectAndReveal(lineInfo.getOffset(), lineInfo.getLength()); - } - } - } catch (JavaModelException e) { - } catch (PartInitException e) { - } catch (BadLocationException e) { - } - } - - /** - * Returns the list of android-flagged projects. This list contains projects that are opened - * in the workspace and that are flagged as android project (through the android nature) - * @return an array of IJavaProject, which can be empty if no projects match. - */ - public static IJavaProject[] getAndroidProjects() { - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - - return getAndroidProjects(javaModel); - } - - /** - * Returns the list of android-flagged projects for the specified java Model. - * This list contains projects that are opened in the workspace and that are flagged as android - * project (through the android nature) - * @param javaModel the Java Model object corresponding for the current workspace root. - * @return an array of IJavaProject, which can be empty if no projects match. - */ - public static IJavaProject[] getAndroidProjects(IJavaModel javaModel) { - // get the java projects - IJavaProject[] javaProjectList = null; - try { - javaProjectList = javaModel.getJavaProjects(); - } - catch (JavaModelException jme) { - return new IJavaProject[0]; - } - - // temp list to build the android project array - ArrayList<IJavaProject> androidProjectList = new ArrayList<IJavaProject>(); - - // loop through the projects and add the android flagged projects to the temp list. - for (IJavaProject javaProject : javaProjectList) { - // get the workspace project object - IProject project = javaProject.getProject(); - - // check if it's an android project based on its nature - try { - if (project.hasNature(AndroidConstants.NATURE)) { - androidProjectList.add(javaProject); - } - } catch (CoreException e) { - // this exception, thrown by IProject.hasNature(), means the project either doesn't - // exist or isn't opened. So, in any case we just skip it (the exception will - // bypass the ArrayList.add() - } - } - - // return the android projects list. - return androidProjectList.toArray(new IJavaProject[androidProjectList.size()]); - } - - /** - * Returns the {@link IFolder} representing the output for the project. - * <p> - * The project must be a java project and be opened, or the method will return null. - * @param project the {@link IProject} - * @return an IFolder item or null. - */ - public final static IFolder getOutputFolder(IProject project) { - try { - if (project.isOpen() && project.hasNature(JavaCore.NATURE_ID)) { - // get a java project from the normal project object - IJavaProject javaProject = JavaCore.create(project); - - IPath path = javaProject.getOutputLocation(); - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - IResource outputResource = wsRoot.findMember(path); - if (outputResource != null && outputResource.getType() == IResource.FOLDER) { - return (IFolder)outputResource; - } - } - } catch (JavaModelException e) { - // Let's do nothing and return null - } catch (CoreException e) { - // Let's do nothing and return null - } - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/ExportHelper.java deleted file mode 100644 index 4b169a1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/ExportHelper.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2008 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.common.project; - -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.FileDialog; -import org.eclipse.swt.widgets.Shell; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.jar.JarEntry; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -/** - * Export helper for project. - */ -public final class ExportHelper { - - private static IExportCallback sCallback; - - public interface IExportCallback { - void startExportWizard(IProject project); - } - - public static void setCallback(IExportCallback callback) { - sCallback = callback; - } - - public static void startExportWizard(IProject project) { - if (sCallback != null) { - sCallback.startExportWizard(project); - } - } - - /** - * Exports an <b>unsigned</b> version of the application created by the given project. - * @param project the project to export - */ - public static void exportProject(IProject project) { - Shell shell = Display.getCurrent().getActiveShell(); - - // get the java project to get the output directory - IFolder outputFolder = BaseProjectHelper.getOutputFolder(project); - if (outputFolder != null) { - IPath binLocation = outputFolder.getLocation(); - - // make the full path to the package - String fileName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE; - - File file = new File(binLocation.toOSString() + File.separator + fileName); - - if (file.exists() == false || file.isFile() == false) { - MessageDialog.openInformation(Display.getCurrent().getActiveShell(), - "Android IDE Plug-in", - String.format("Failed to export %1$s: %2$s doesn't exist!", - project.getName(), file.getPath())); - return; - } - - // ok now pop up the file save window - FileDialog fileDialog = new FileDialog(shell, SWT.SAVE); - - fileDialog.setText("Export Project"); - fileDialog.setFileName(fileName); - - String saveLocation = fileDialog.open(); - if (saveLocation != null) { - // get the stream from the original file - - ZipInputStream zis = null; - ZipOutputStream zos = null; - FileInputStream input = null; - FileOutputStream output = null; - - try { - input = new FileInputStream(file); - zis = new ZipInputStream(input); - - // get an output stream into the new file - File saveFile = new File(saveLocation); - output = new FileOutputStream(saveFile); - zos = new ZipOutputStream(output); - } catch (FileNotFoundException e) { - // only the input/output stream are throwing this exception. - // so we only have to close zis if output is the one that threw. - if (zis != null) { - try { - zis.close(); - } catch (IOException e1) { - // pass - } - } - - MessageDialog.openInformation(shell, "Android IDE Plug-in", - String.format("Failed to export %1$s: %2$s doesn't exist!", - project.getName(), file.getPath())); - return; - } - - try { - ZipEntry entry; - - byte[] buffer = new byte[4096]; - - while ((entry = zis.getNextEntry()) != null) { - String name = entry.getName(); - - // do not take directories or anything inside the META-INF folder since - // we want to strip the signature. - if (entry.isDirectory() || name.startsWith("META-INF/")) { //$NON-NL1$ - continue; - } - - ZipEntry newEntry; - - // Preserve the STORED method of the input entry. - if (entry.getMethod() == JarEntry.STORED) { - newEntry = new JarEntry(entry); - } else { - // Create a new entry so that the compressed len is recomputed. - newEntry = new JarEntry(name); - } - - // add the entry to the jar archive - zos.putNextEntry(newEntry); - - // read the content of the entry from the input stream, and write it into the archive. - int count; - while ((count = zis.read(buffer)) != -1) { - zos.write(buffer, 0, count); - } - - // close the entry for this file - zos.closeEntry(); - zis.closeEntry(); - - } - - } catch (IOException e) { - MessageDialog.openInformation(shell, "Android IDE Plug-in", - String.format("Failed to export %1$s: %2$s", - project.getName(), e.getMessage())); - } finally { - try { - zos.close(); - } catch (IOException e) { - // pass - } - try { - zis.close(); - } catch (IOException e) { - // pass - } - } - } - } else { - MessageDialog.openInformation(shell, "Android IDE Plug-in", - String.format("Failed to export %1$s: Could not get project output location", - project.getName())); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/ProjectChooserHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/ProjectChooserHelper.java deleted file mode 100644 index 0c43499..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/ProjectChooserHelper.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2008 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.common.project; - -import com.android.ide.eclipse.common.project.BaseProjectHelper; - -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.ui.JavaElementLabelProvider; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.dialogs.ElementListSelectionDialog; - -/** - * Helper class to deal with displaying a project choosing dialog that lists only the - * projects with the Android nature. - */ -public class ProjectChooserHelper { - - private final Shell mParentShell; - - /** - * List of current android projects. Since the dialog is modal, we'll just get - * the list once on-demand. - */ - private IJavaProject[] mAndroidProjects; - - public ProjectChooserHelper(Shell parentShell) { - mParentShell = parentShell; - } - /** - * Displays a project chooser dialog which lists all available projects with the Android nature. - * <p/> - * The list of project is built from Android flagged projects currently opened in the workspace. - * - * @param projectName If non null and not empty, represents the name of an Android project - * that will be selected by default. - * @return the project chosen by the user in the dialog, or null if the dialog was canceled. - */ - public IJavaProject chooseJavaProject(String projectName) { - ILabelProvider labelProvider = new JavaElementLabelProvider( - JavaElementLabelProvider.SHOW_DEFAULT); - ElementListSelectionDialog dialog = new ElementListSelectionDialog( - mParentShell, labelProvider); - dialog.setTitle("Project Selection"); - dialog.setMessage("Select a project to constrain your search."); - - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - - // set the elements in the dialog. These are opened android projects. - dialog.setElements(getAndroidProjects(javaModel)); - - // look for the project matching the given project name - IJavaProject javaProject = null; - if (projectName != null && projectName.length() > 0) { - javaProject = javaModel.getJavaProject(projectName); - } - - // if we found it, we set the initial selection in the dialog to this one. - if (javaProject != null) { - dialog.setInitialSelections(new Object[] { javaProject }); - } - - // open the dialog and return the object selected if OK was clicked, or null otherwise - if (dialog.open() == Window.OK) { - return (IJavaProject)dialog.getFirstResult(); - } - return null; - } - - /** - * Returns the list of Android projects. - * <p/> - * Because this list can be time consuming, this class caches the list of project. - * It is recommended to call this method instead of - * {@link BaseProjectHelper#getAndroidProjects()}. - * - * @param javaModel the java model. Can be null. - */ - public IJavaProject[] getAndroidProjects(IJavaModel javaModel) { - if (mAndroidProjects == null) { - if (javaModel == null) { - mAndroidProjects = BaseProjectHelper.getAndroidProjects(); - } else { - mAndroidProjects = BaseProjectHelper.getAndroidProjects(javaModel); - } - } - - return mAndroidProjects; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java deleted file mode 100644 index fda55c4..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2007 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.common.project; - -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * XML error handler used by the parser to report errors/warnings. - */ -public class XmlErrorHandler extends DefaultHandler { - - /** file being parsed */ - private IFile mFile; - - /** link to the delta visitor, to set the xml error flag */ - private XmlErrorListener mErrorListener; - - /** - * Classes which implement this interface provide a method that deals - * with XML errors. - */ - public interface XmlErrorListener { - /** - * Sent when an XML error is detected. - */ - public void errorFound(); - } - - public static class BasicXmlErrorListener implements XmlErrorListener { - public boolean mHasXmlError = false; - - public void errorFound() { - mHasXmlError = true; - } - } - - public XmlErrorHandler(IFile file, XmlErrorListener errorListener) { - mFile = file; - mErrorListener = errorListener; - } - - /** - * Xml Error call back - * @param exception the parsing exception - * @throws SAXException - */ - @Override - public void error(SAXParseException exception) throws SAXException { - handleError(exception, exception.getLineNumber()); - } - - /** - * Xml Fatal Error call back - * @param exception the parsing exception - * @throws SAXException - */ - @Override - public void fatalError(SAXParseException exception) throws SAXException { - handleError(exception, exception.getLineNumber()); - } - - /** - * Xml Warning call back - * @param exception the parsing exception - * @throws SAXException - */ - @Override - public void warning(SAXParseException exception) throws SAXException { - BaseProjectHelper.addMarker(mFile, AndroidConstants.MARKER_XML, exception.getMessage(), - exception.getLineNumber(), IMarker.SEVERITY_WARNING); - } - - protected final IFile getFile() { - return mFile; - } - - /** - * Handles a parsing error and an optional line number. - * @param exception - * @param lineNumber - */ - protected void handleError(Exception exception, int lineNumber) { - if (mErrorListener != null) { - mErrorListener.errorFound(); - } - - if (lineNumber != -1) { - BaseProjectHelper.addMarker(mFile, AndroidConstants.MARKER_XML, exception.getMessage(), - lineNumber, IMarker.SEVERITY_ERROR); - } else { - BaseProjectHelper.addMarker(mFile, AndroidConstants.MARKER_XML, exception.getMessage(), - IMarker.SEVERITY_ERROR); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java deleted file mode 100644 index 3875e81..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (C) 2008 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.common.resources; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo.Format; -import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; - -import org.eclipse.core.runtime.IStatus; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.TreeSet; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -/** - * Parser for attributes description files. - */ -public final class AttrsXmlParser { - - private Document mDocument; - private String mOsAttrsXmlPath; - // all attributes that have the same name are supposed to have the same - // parameters so we'll keep a cache of them to avoid processing them twice. - private HashMap<String, AttributeInfo> mAttributeMap; - - /** Map of all attribute names for a given element */ - private HashMap<String, DeclareStyleableInfo> mStyleMap; - - /** Map of all (constant, value) pairs for attributes of format enum or flag. - * E.g. for attribute name=gravity, this tells us there's an enum/flag called "center" - * with value 0x11. - */ - private Map<String, Map<String, Integer>> mEnumFlagValues; - - - /** - * Creates a new {@link AttrsXmlParser}, set to load things from the given - * XML file. Nothing has been parsed yet. Callers should call {@link #preload()} - * next. - */ - public AttrsXmlParser(String osAttrsXmlPath) { - this(osAttrsXmlPath, null /* inheritableAttributes */); - } - - /** - * Creates a new {@link AttrsXmlParser} set to load things from the given - * XML file. If inheritableAttributes is non-null, it must point to a preloaded - * {@link AttrsXmlParser} which attributes will be used for this one. Since - * already defined attributes are not modifiable, they are thus "inherited". - */ - public AttrsXmlParser(String osAttrsXmlPath, AttrsXmlParser inheritableAttributes) { - mOsAttrsXmlPath = osAttrsXmlPath; - - // styles are not inheritable. - mStyleMap = new HashMap<String, DeclareStyleableInfo>(); - - if (inheritableAttributes == null) { - mAttributeMap = new HashMap<String, AttributeInfo>(); - mEnumFlagValues = new HashMap<String, Map<String,Integer>>(); - } else { - mAttributeMap = new HashMap<String, AttributeInfo>(inheritableAttributes.mAttributeMap); - mEnumFlagValues = new HashMap<String, Map<String,Integer>>( - inheritableAttributes.mEnumFlagValues); - } - } - - /** - * @return The OS path of the attrs.xml file parsed - */ - public String getOsAttrsXmlPath() { - return mOsAttrsXmlPath; - } - - /** - * Preloads the document, parsing all attributes and declared styles. - * - * @return Self, for command chaining. - */ - public AttrsXmlParser preload() { - Document doc = getDocument(); - - if (doc == null) { - AdtPlugin.log(IStatus.WARNING, "Failed to find %1$s", //$NON-NLS-1$ - mOsAttrsXmlPath); - return this; - } - - Node res = doc.getFirstChild(); - while (res != null && - res.getNodeType() != Node.ELEMENT_NODE && - !res.getNodeName().equals("resources")) { //$NON-NLS-1$ - res = res.getNextSibling(); - } - - if (res == null) { - AdtPlugin.log(IStatus.WARNING, "Failed to find a <resources> node in %1$s", //$NON-NLS-1$ - mOsAttrsXmlPath); - return this; - } - - parseResources(res); - return this; - } - - /** - * Loads all attributes & javadoc for the view class info based on the class name. - */ - public void loadViewAttributes(ViewClassInfo info) { - if (getDocument() != null) { - String xmlName = info.getShortClassName(); - DeclareStyleableInfo style = mStyleMap.get(xmlName); - if (style != null) { - info.setAttributes(style.getAttributes()); - info.setJavaDoc(style.getJavaDoc()); - } - } - } - - /** - * Loads all attributes for the layout data info based on the class name. - */ - public void loadLayoutParamsAttributes(LayoutParamsInfo info) { - if (getDocument() != null) { - // Transforms "LinearLayout" and "LayoutParams" into "LinearLayout_Layout". - String xmlName = String.format("%1$s_%2$s", //$NON-NLS-1$ - info.getViewLayoutClass().getShortClassName(), - info.getShortClassName()); - xmlName = xmlName.replaceFirst("Params$", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - DeclareStyleableInfo style = mStyleMap.get(xmlName); - if (style != null) { - info.setAttributes(style.getAttributes()); - } - } - } - - /** - * Returns a list of all decleare-styleable found in the xml file. - */ - public Map<String, DeclareStyleableInfo> getDeclareStyleableList() { - return Collections.unmodifiableMap(mStyleMap); - } - - /** - * Returns a map of all enum and flag constants sorted by parent attribute name. - * The map is attribute_name => (constant_name => integer_value). - */ - public Map<String, Map<String, Integer>> getEnumFlagValues() { - return mEnumFlagValues; - } - - //------------------------- - - /** - * Creates an XML document from the attrs.xml OS path. - * May return null if the file doesn't exist or cannot be parsed. - */ - private Document getDocument() { - if (mDocument == null) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setIgnoringComments(false); - try { - DocumentBuilder builder = factory.newDocumentBuilder(); - mDocument = builder.parse(new File(mOsAttrsXmlPath)); - } catch (ParserConfigurationException e) { - AdtPlugin.log(e, "Failed to create XML document builder for %1$s", //$NON-NLS-1$ - mOsAttrsXmlPath); - } catch (SAXException e) { - AdtPlugin.log(e, "Failed to parse XML document %1$s", //$NON-NLS-1$ - mOsAttrsXmlPath); - } catch (IOException e) { - AdtPlugin.log(e, "Failed to read XML document %1$s", //$NON-NLS-1$ - mOsAttrsXmlPath); - } - } - return mDocument; - } - - /** - * Finds all the <declare-styleable> and <attr> nodes in the top <resources> node. - */ - private void parseResources(Node res) { - Node lastComment = null; - for (Node node = res.getFirstChild(); node != null; node = node.getNextSibling()) { - switch (node.getNodeType()) { - case Node.COMMENT_NODE: - lastComment = node; - break; - case Node.ELEMENT_NODE: - if (node.getNodeName().equals("declare-styleable")) { //$NON-NLS-1$ - Node nameNode = node.getAttributes().getNamedItem("name"); //$NON-NLS-1$ - if (nameNode != null) { - String name = nameNode.getNodeValue(); - - Node parentNode = node.getAttributes().getNamedItem("parent"); //$NON-NLS-1$ - String parents = parentNode == null ? null : parentNode.getNodeValue(); - - if (name != null && !mStyleMap.containsKey(name)) { - DeclareStyleableInfo style = parseDeclaredStyleable(name, node); - if (parents != null) { - style.setParents(parents.split("[ ,|]")); //$NON-NLS-1$ - } - mStyleMap.put(name, style); - if (lastComment != null) { - style.setJavaDoc(parseJavadoc(lastComment.getNodeValue())); - } - } - } - } else if (node.getNodeName().equals("attr")) { //$NON-NLS-1$ - parseAttr(node, lastComment); - } - lastComment = null; - break; - } - } - } - - /** - * Parses an <attr> node and convert it into an {@link AttributeInfo} if it is valid. - */ - private AttributeInfo parseAttr(Node attrNode, Node lastComment) { - AttributeInfo info = null; - Node nameNode = attrNode.getAttributes().getNamedItem("name"); //$NON-NLS-1$ - if (nameNode != null) { - String name = nameNode.getNodeValue(); - if (name != null) { - info = mAttributeMap.get(name); - // If the attribute is unknown yet, parse it. - // If the attribute is know but its format is unknown, parse it too. - if (info == null || info.getFormats().length == 0) { - info = parseAttributeTypes(attrNode, name); - if (info != null) { - mAttributeMap.put(name, info); - } - } else if (lastComment != null) { - info = new AttributeInfo(info); - } - if (info != null) { - if (lastComment != null) { - info.setJavaDoc(parseJavadoc(lastComment.getNodeValue())); - info.setDeprecatedDoc(parseDeprecatedDoc(lastComment.getNodeValue())); - } - } - } - } - return info; - } - - /** - * Finds all the attributes for a particular style node, - * e.g. a declare-styleable of name "TextView" or "LinearLayout_Layout". - * - * @param styleName The name of the declare-styleable node - * @param declareStyleableNode The declare-styleable node itself - */ - private DeclareStyleableInfo parseDeclaredStyleable(String styleName, - Node declareStyleableNode) { - ArrayList<AttributeInfo> attrs = new ArrayList<AttributeInfo>(); - Node lastComment = null; - for (Node node = declareStyleableNode.getFirstChild(); - node != null; - node = node.getNextSibling()) { - - switch (node.getNodeType()) { - case Node.COMMENT_NODE: - lastComment = node; - break; - case Node.ELEMENT_NODE: - if (node.getNodeName().equals("attr")) { //$NON-NLS-1$ - AttributeInfo info = parseAttr(node, lastComment); - if (info != null) { - attrs.add(info); - } - } - lastComment = null; - break; - } - - } - - return new DeclareStyleableInfo(styleName, attrs.toArray(new AttributeInfo[attrs.size()])); - } - - /** - * Returns the {@link AttributeInfo} for a specific <attr> XML node. - * This gets the javadoc, the type, the name and the enum/flag values if any. - * <p/> - * The XML node is expected to have the following attributes: - * <ul> - * <li>"name", which is mandatory. The node is skipped if this is missing.</li> - * <li>"format".</li> - * </ul> - * The format may be one type or two types (e.g. "reference|color"). - * An extra format can be implied: "enum" or "flag" are not specified in the "format" attribute, - * they are implicitely stated by the presence of sub-nodes <enum> or <flag>. - * <p/> - * By design, <attr> nodes of the same name MUST have the same type. - * Attribute nodes are thus cached by name and reused as much as possible. - * When reusing a node, it is duplicated and its javadoc reassigned. - */ - private AttributeInfo parseAttributeTypes(Node attrNode, String name) { - TreeSet<AttributeInfo.Format> formats = new TreeSet<AttributeInfo.Format>(); - String[] enumValues = null; - String[] flagValues = null; - - Node attrFormat = attrNode.getAttributes().getNamedItem("format"); //$NON-NLS-1$ - if (attrFormat != null) { - for (String f : attrFormat.getNodeValue().split("\\|")) { //$NON-NLS-1$ - try { - Format format = AttributeInfo.Format.valueOf(f.toUpperCase()); - // enum and flags are handled differently right below - if (format != null && - format != AttributeInfo.Format.ENUM && - format != AttributeInfo.Format.FLAG) { - formats.add(format); - } - } catch (IllegalArgumentException e) { - AdtPlugin.log(e, "Unknown format name '%s' in <attr name=\"%s\">, file '%s'.", //$NON-NLS-1$ - f, name, getOsAttrsXmlPath()); - } - } - } - - // does this <attr> have <enum> children? - enumValues = parseEnumFlagValues(attrNode, "enum", name); //$NON-NLS-1$ - if (enumValues != null) { - formats.add(AttributeInfo.Format.ENUM); - } - - // does this <attr> have <flag> children? - flagValues = parseEnumFlagValues(attrNode, "flag", name); //$NON-NLS-1$ - if (flagValues != null) { - formats.add(AttributeInfo.Format.FLAG); - } - - AttributeInfo info = new AttributeInfo(name, - formats.toArray(new AttributeInfo.Format[formats.size()])); - info.setEnumValues(enumValues); - info.setFlagValues(flagValues); - return info; - } - - /** - * Given an XML node that represents an <attr> node, this method searches - * if the node has any children nodes named "target" (e.g. "enum" or "flag"). - * Such nodes must have a "name" attribute. - * <p/> - * If "attrNode" is null, look for any <attr> that has the given attrNode - * and the requested children nodes. - * <p/> - * This method collects all the possible names of these children nodes and - * return them. - * - * @param attrNode The <attr> XML node - * @param filter The child node to look for, either "enum" or "flag". - * @param attrName The value of the name attribute of <attr> - * - * @return Null if there are no such children nodes, otherwise an array of length >= 1 - * of all the names of these children nodes. - */ - private String[] parseEnumFlagValues(Node attrNode, String filter, String attrName) { - ArrayList<String> names = null; - for (Node child = attrNode.getFirstChild(); child != null; child = child.getNextSibling()) { - if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(filter)) { - Node nameNode = child.getAttributes().getNamedItem("name"); //$NON-NLS-1$ - if (nameNode == null) { - AdtPlugin.log(IStatus.WARNING, - "Missing name attribute in <attr name=\"%s\"><%s></attr>", //$NON-NLS-1$ - attrName, filter); - } else { - if (names == null) { - names = new ArrayList<String>(); - } - String name = nameNode.getNodeValue(); - names.add(name); - - Node valueNode = child.getAttributes().getNamedItem("value"); //$NON-NLS-1$ - if (valueNode == null) { - AdtPlugin.log(IStatus.WARNING, - "Missing value attribute in <attr name=\"%s\"><%s name=\"%s\"></attr>", //$NON-NLS-1$ - attrName, filter, name); - } else { - String value = valueNode.getNodeValue(); - try { - int i = value.startsWith("0x") ? - Integer.parseInt(value.substring(2), 16 /* radix */) : - Integer.parseInt(value); - - Map<String, Integer> map = mEnumFlagValues.get(attrName); - if (map == null) { - map = new HashMap<String, Integer>(); - mEnumFlagValues.put(attrName, map); - } - map.put(name, Integer.valueOf(i)); - - } catch(NumberFormatException e) { - AdtPlugin.log(e, - "Value in <attr name=\"%s\"><%s name=\"%s\" value=\"%s\"></attr> is not a valid decimal or hexadecimal", //$NON-NLS-1$ - attrName, filter, name, value); - } - } - } - } - } - return names == null ? null : names.toArray(new String[names.size()]); - } - - /** - * Parses the javadoc comment. - * Only keeps the first sentence. - * <p/> - * This does not remove nor simplify links and references. Such a transformation - * is done later at "display" time in {@link DescriptorsUtils#formatTooltip(String)} and co. - */ - private String parseJavadoc(String comment) { - if (comment == null) { - return null; - } - - // sanitize & collapse whitespace - comment = comment.replaceAll("\\s+", " "); //$NON-NLS-1$ //$NON-NLS-2$ - - // Explicitly remove any @deprecated tags since they are handled separately. - comment = comment.replaceAll("(?:\\{@deprecated[^}]*\\}|@deprecated[^@}]*)", ""); - - // take everything up to the first dot that is followed by a space or the end of the line. - // I love regexps :-). For the curious, the regexp is: - // - start of line - // - ignore whitespace - // - group: - // - everything, not greedy - // - non-capturing group (?: ) - // - end of string - // or - // - not preceded by a letter, a dot and another letter (for "i.e" and "e.g" ) - // (<! non-capturing zero-width negative look-behind) - // - a dot - // - followed by a space (?= non-capturing zero-width positive look-ahead) - // - anything else is ignored - comment = comment.replaceFirst("^\\s*(.*?(?:$|(?<![a-zA-Z]\\.[a-zA-Z])\\.(?=\\s))).*", "$1"); //$NON-NLS-1$ //$NON-NLS-2$ - - return comment; - } - - - /** - * Parses the javadoc and extract the first @deprecated tag, if any. - * Returns null if there's no @deprecated tag. - * The deprecated tag can be of two forms: - * - {+@deprecated ...text till the next bracket } - * Note: there should be no space or + between { and @. I need one in this comment otherwise - * this method will be tagged as deprecated ;-) - * - @deprecated ...text till the next @tag or end of the comment. - * In both cases the comment can be multi-line. - */ - private String parseDeprecatedDoc(String comment) { - // Skip if we can't even find the tag in the comment. - if (comment == null) { - return null; - } - - // sanitize & collapse whitespace - comment = comment.replaceAll("\\s+", " "); //$NON-NLS-1$ //$NON-NLS-2$ - - int pos = comment.indexOf("{@deprecated"); - if (pos >= 0) { - comment = comment.substring(pos + 12 /* len of {@deprecated */); - comment = comment.replaceFirst("^([^}]*).*", "$1"); - } else if ((pos = comment.indexOf("@deprecated")) >= 0) { - comment = comment.substring(pos + 11 /* len of @deprecated */); - comment = comment.replaceFirst("^(.*?)(?:@.*|$)", "$1"); - } else { - return null; - } - - return comment.trim(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java deleted file mode 100644 index efa5981..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2008 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.common.resources; - - -/** - * Information needed to represent a View or ViewGroup (aka Layout) item - * in the layout hierarchy, as extracted from the main android.jar and the - * associated attrs.xml. - */ -public class DeclareStyleableInfo { - /** The style name, never null. */ - private String mStyleName; - /** Attributes for this view or view group. Can be empty but never null. */ - private AttributeInfo[] mAttributes; - /** Short javadoc. Can be null. */ - private String mJavaDoc; - /** Optional name of the parents stylable. Can be null. */ - private String[] mParents; - - public static class AttributeInfo { - /** XML Name of the attribute */ - private String mName; - - public enum Format { - STRING, - BOOLEAN, - INTEGER, - FLOAT, - REFERENCE, - COLOR, - DIMENSION, - FRACTION, - ENUM, - FLAG, - } - - /** Formats of the attribute. Cannot be null. Should have at least one format. */ - private Format[] mFormats; - /** Values for enum. null for other types. */ - private String[] mEnumValues; - /** Values for flag. null for other types. */ - private String[] mFlagValues; - /** Short javadoc (i.e. the first sentence). */ - private String mJavaDoc; - /** Documentation for deprecated attributes. Null if not deprecated. */ - private String mDeprecatedDoc; - - /** - * @param name The XML Name of the attribute - * @param formats The formats of the attribute. Cannot be null. - * Should have at least one format. - */ - public AttributeInfo(String name, Format[] formats) { - mName = name; - mFormats = formats; - } - - public AttributeInfo(AttributeInfo info) { - mName = info.mName; - mFormats = info.mFormats; - mEnumValues = info.mEnumValues; - mFlagValues = info.mFlagValues; - mJavaDoc = info.mJavaDoc; - mDeprecatedDoc = info.mDeprecatedDoc; - } - - /** Returns the XML Name of the attribute */ - public String getName() { - return mName; - } - /** Returns the formats of the attribute. Cannot be null. - * Should have at least one format. */ - public Format[] getFormats() { - return mFormats; - } - /** Returns the values for enums. null for other types. */ - public String[] getEnumValues() { - return mEnumValues; - } - /** Returns the values for flags. null for other types. */ - public String[] getFlagValues() { - return mFlagValues; - } - /** Returns a short javadoc, .i.e. the first sentence. */ - public String getJavaDoc() { - return mJavaDoc; - } - /** Returns the documentation for deprecated attributes. Null if not deprecated. */ - public String getDeprecatedDoc() { - return mDeprecatedDoc; - } - - /** Sets the values for enums. null for other types. */ - public void setEnumValues(String[] values) { - mEnumValues = values; - } - /** Sets the values for flags. null for other types. */ - public void setFlagValues(String[] values) { - mFlagValues = values; - } - /** Sets a short javadoc, .i.e. the first sentence. */ - public void setJavaDoc(String javaDoc) { - mJavaDoc = javaDoc; - } - /** Sets the documentation for deprecated attributes. Null if not deprecated. */ - public void setDeprecatedDoc(String deprecatedDoc) { - mDeprecatedDoc = deprecatedDoc; - } - - } - - // -------- - - /** - * Creates a new {@link DeclareStyleableInfo}. - * - * @param styleName The name of the style. Should not be empty nor null. - * @param attributes The initial list of attributes. Can be null. - */ - public DeclareStyleableInfo(String styleName, AttributeInfo[] attributes) { - mStyleName = styleName; - mAttributes = attributes == null ? new AttributeInfo[0] : attributes; - } - - /** Returns style name */ - public String getStyleName() { - return mStyleName; - } - - /** Returns the attributes for this view or view group. Maybe empty but not null. */ - public AttributeInfo[] getAttributes() { - return mAttributes; - } - - /** Sets the list of attributes for this View or ViewGroup. */ - public void setAttributes(AttributeInfo[] attributes) { - mAttributes = attributes; - } - - /** Returns a short javadoc */ - public String getJavaDoc() { - return mJavaDoc; - } - - /** Sets the javadoc. */ - public void setJavaDoc(String javaDoc) { - mJavaDoc = javaDoc; - } - - /** Sets the name of the parents styleable. Can be null. */ - public void setParents(String[] parents) { - mParents = parents; - } - - /** Returns the name of the parents styleable. Can be null. */ - public String[] getParents() { - return mParents; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IIdResourceItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IIdResourceItem.java deleted file mode 100644 index 38b7e03..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IIdResourceItem.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2008 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.common.resources; - -/** - * Classes which implements this interface provides a method indicating the state of a resource of - * type {@link ResourceType#ID}. - */ -public interface IIdResourceItem { - /** - * Returns whether the ID resource has been declared inline inside another resource XML file. - */ - public boolean isDeclaredInline(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IPathChangedListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IPathChangedListener.java deleted file mode 100644 index 53d9077..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IPathChangedListener.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2008 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.common.resources; - -/** - * Classes which implement this interface provide a method that deals with - * a path change. - */ -public interface IPathChangedListener { - /** - * Sent when the location of the android sdk directory changed. - * @param osPath The new android sdk directory location. - */ - public void pathChanged(String osPath); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IResourceRepository.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IResourceRepository.java deleted file mode 100644 index 3819997..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/IResourceRepository.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2007 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.common.resources; - -/** - * A repository of resources. This allows access to the resource by {@link ResourceType}. - */ -public interface IResourceRepository { - - /** - * Returns the present {@link ResourceType}s in the project. - * @return an array containing all the type of resources existing in the project. - */ - public abstract ResourceType[] getAvailableResourceTypes(); - - /** - * Returns an array of the existing resource for the specified type. - * @param type the type of the resources to return - */ - public abstract ResourceItem[] getResources(ResourceType type); - - /** - * Returns whether resources of the specified type are present. - * @param type the type of the resources to check. - */ - public abstract boolean hasResources(ResourceType type); - - /** - * Returns whether the repository is a system repository. - */ - public abstract boolean isSystemRepository(); - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ResourceItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ResourceItem.java deleted file mode 100644 index 83527f3..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ResourceItem.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008 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.common.resources; - -/** - * Base class representing a Resource Item, as returned by a {@link IResourceRepository}. - */ -public class ResourceItem implements Comparable<ResourceItem> { - - private final String mName; - - /** - * Constructs a new ResourceItem - * @param name the name of the resource as it appears in the XML and R.java files. - */ - public ResourceItem(String name) { - mName = name; - } - - /** - * Returns the name of the resource item. - */ - public final String getName() { - return mName; - } - - /** - * Compares the {@link ResourceItem} to another. - * @param other the ResourceItem to be compared to. - */ - public int compareTo(ResourceItem other) { - return mName.compareTo(other.mName); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ResourceType.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ResourceType.java deleted file mode 100644 index 60c471e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ResourceType.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2007 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.common.resources; - -/** - * Enum representing a type of compiled resource. - */ -public enum ResourceType { - ANIM("anim", "Animation"), //$NON-NLS-1$ - ARRAY("array", "Array", "string-array", "integer-array"), //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$ - ATTR("attr", "Attr"), //$NON-NLS-1$ - COLOR("color", "Color"), //$NON-NLS-1$ - DIMEN("dimen", "Dimension"), //$NON-NLS-1$ - DRAWABLE("drawable", "Drawable"), //$NON-NLS-1$ - ID("id", "ID"), //$NON-NLS-1$ - LAYOUT("layout", "Layout"), //$NON-NLS-1$ - MENU("menu", "Menu"), //$NON-NLS-1$ - RAW("raw", "Raw"), //$NON-NLS-1$ - STRING("string", "String"), //$NON-NLS-1$ - STYLE("style", "Style"), //$NON-NLS-1$ - STYLEABLE("styleable", "Styleable"), //$NON-NLS-1$ - XML("xml", "XML"); //$NON-NLS-1$ - - private final String mName; - private final String mDisplayName; - private final String[] mAlternateXmlNames; - - ResourceType(String name, String displayName, String... alternateXmlNames) { - mName = name; - mDisplayName = displayName; - mAlternateXmlNames = alternateXmlNames; - } - - /** - * Returns the resource type name, as used by XML files. - */ - public String getName() { - return mName; - } - - /** - * Returns a translated display name for the resource type. - */ - public String getDisplayName() { - return mDisplayName; - } - - /** - * Returns the enum by its name as it appears in the XML or the R class. - * @param name name of the resource - * @return the matching {@link ResourceType} or <code>null</code> if no match was found. - */ - public static ResourceType getEnum(String name) { - for (ResourceType rType : values()) { - if (rType.mName.equals(name)) { - return rType; - } else if (rType.mAlternateXmlNames != null) { - // if there are alternate Xml Names, we test those too - for (String alternate : rType.mAlternateXmlNames) { - if (alternate.equals(name)) { - return rType; - } - } - } - } - return null; - } - - /** - * Returns a formatted string usable in an XML to use the specified {@link ResourceItem}. - * @param resourceItem The resource item. - * @param system Whether this is a system resource or a project resource. - * @return a string in the format @[type]/[name] - */ - public String getXmlString(ResourceItem resourceItem, boolean system) { - if (this == ID && resourceItem instanceof IIdResourceItem) { - IIdResourceItem idResource = (IIdResourceItem)resourceItem; - if (idResource.isDeclaredInline()) { - return (system?"@android:":"@+") + mName + "/" + resourceItem.getName(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - } - - return (system?"@android:":"@") + mName + "/" + resourceItem.getName(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - /** - * Returns an array with all the names defined by this enum. - */ - public static String[] getNames() { - ResourceType[] values = values(); - String[] names = new String[values.length]; - for (int i = values.length - 1; i >= 0; --i) { - names[i] = values[i].getName(); - } - return names; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ViewClassInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ViewClassInfo.java deleted file mode 100644 index 619e3cc..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/ViewClassInfo.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2008 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.common.resources; - -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo; - -/** - * Information needed to represent a View or ViewGroup (aka Layout) item - * in the layout hierarchy, as extracted from the main android.jar and the - * associated attrs.xml. - */ -public class ViewClassInfo { - /** Is this a layout class (i.e. ViewGroup) or just a view? */ - private boolean mIsLayout; - /** FQCN e.g. android.view.View, never null. */ - private String mCanonicalClassName; - /** Short class name, e.g. View, never null. */ - private String mShortClassName; - /** Super class. Can be null. */ - private ViewClassInfo mSuperClass; - /** Short javadoc. Can be null. */ - private String mJavaDoc; - /** Attributes for this view or view group. Can be empty but never null. */ - private AttributeInfo[] mAttributes; - - public static class LayoutParamsInfo { - /** Short class name, e.g. LayoutData, never null. */ - private String mShortClassName; - /** ViewLayout class info owning this layout data */ - private ViewClassInfo mViewLayoutClass; - /** Super class. Can be null. */ - private LayoutParamsInfo mSuperClass; - /** Layout Data Attributes for layout classes. Can be empty but not null. */ - private AttributeInfo[] mAttributes; - - public LayoutParamsInfo(ViewClassInfo enclosingViewClassInfo, - String shortClassName, LayoutParamsInfo superClassInfo) { - mShortClassName = shortClassName; - mViewLayoutClass = enclosingViewClassInfo; - mSuperClass = superClassInfo; - mAttributes = new AttributeInfo[0]; - } - - /** Returns short class name, e.g. "LayoutData" */ - public String getShortClassName() { - return mShortClassName; - } - /** Returns the ViewLayout class info enclosing this layout data. Cannot null. */ - public ViewClassInfo getViewLayoutClass() { - return mViewLayoutClass; - } - /** Returns the super class info. Can be null. */ - public LayoutParamsInfo getSuperClass() { - return mSuperClass; - } - /** Returns the LayoutData attributes. Can be empty but not null. */ - public AttributeInfo[] getAttributes() { - return mAttributes; - } - /** Sets the LayoutData attributes. Can be empty but not null. */ - public void setAttributes(AttributeInfo[] attributes) { - mAttributes = attributes; - } - } - - /** Layout data info for a layout class. Null for all non-layout classes and always - * non-null for a layout class. */ - public LayoutParamsInfo mLayoutData; - - // -------- - - public ViewClassInfo(boolean isLayout, String canonicalClassName, String shortClassName) { - mIsLayout = isLayout; - mCanonicalClassName = canonicalClassName; - mShortClassName = shortClassName; - mAttributes = new AttributeInfo[0]; - } - - /** Returns whether this is a layout class (i.e. ViewGroup) or just a View */ - public boolean isLayout() { - return mIsLayout; - } - - /** Returns FQCN e.g. "android.view.View" */ - public String getCanonicalClassName() { - return mCanonicalClassName; - } - - /** Returns short class name, e.g. "View" */ - public String getShortClassName() { - return mShortClassName; - } - - /** Returns the super class. Can be null. */ - public ViewClassInfo getSuperClass() { - return mSuperClass; - } - - /** Returns a short javadoc */ - public String getJavaDoc() { - return mJavaDoc; - } - - /** Returns the attributes for this view or view group. Maybe empty but not null. */ - public AttributeInfo[] getAttributes() { - return mAttributes; - } - - /** Returns the LayoutData info for layout classes. Null for non-layout view classes. */ - public LayoutParamsInfo getLayoutData() { - return mLayoutData; - } - - /** - * Sets a link on the info of the super class of this View or ViewGroup. - * <p/> - * The super class info must be of the same kind (i.e. group to group or view to view) - * except for the top ViewGroup which links to the View info. - * <p/> - * The super class cannot be null except for the top View info. - */ - public void setSuperClass(ViewClassInfo superClass) { - mSuperClass = superClass; - } - - /** Sets the javadoc for this View or ViewGroup. */ - public void setJavaDoc(String javaDoc) { - mJavaDoc = javaDoc; - } - - /** Sets the list of attributes for this View or ViewGroup. */ - public void setAttributes(AttributeInfo[] attributes) { - mAttributes = attributes; - } - - /** - * Sets the {@link LayoutParamsInfo} for layout classes. - * Does nothing for non-layout view classes. - */ - public void setLayoutParams(LayoutParamsInfo layoutData) { - if (mIsLayout) { - mLayoutData = layoutData; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java deleted file mode 100644 index a325ccb..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java +++ /dev/null @@ -1,771 +0,0 @@ -/* - * Copyright (C) 2007 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.editors; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextValueDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiFlagAttributeNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.TextSelection; -import org.eclipse.jface.text.contentassist.CompletionProposal; -import org.eclipse.jface.text.contentassist.ICompletionProposal; -import org.eclipse.jface.text.contentassist.IContentAssistProcessor; -import org.eclipse.jface.text.contentassist.IContextInformation; -import org.eclipse.jface.text.contentassist.IContextInformationValidator; -import org.eclipse.jface.text.source.ISourceViewer; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.graphics.Image; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -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.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.regex.Pattern; - -/** - * Content Assist Processor for Android XML files - */ -public abstract class AndroidContentAssist implements IContentAssistProcessor { - - /** Regexp to detect a full attribute after an element tag. - * <pre>Syntax: - * name = "..." quoted string with all but < and " - * or: - * name = '...' quoted string with all but < and ' - * </pre> - */ - private static Pattern sFirstAttribute = Pattern.compile( - "^ *[a-zA-Z_:]+ *= *(?:\"[^<\"]*\"|'[^<']*')"); //$NON-NLS-1$ - - /** Regexp to detect an element tag name */ - private static Pattern sFirstElementWord = Pattern.compile("^[a-zA-Z0-9_:]+"); //$NON-NLS-1$ - - /** Regexp to detect whitespace */ - private static Pattern sWhitespace = Pattern.compile("\\s+"); //$NON-NLS-1$ - - protected final static String ROOT_ELEMENT = ""; - - /** Descriptor of the root of the XML hierarchy. This a "fake" ElementDescriptor which - * is used to list all the possible roots given by actual implementations. - * DO NOT USE DIRECTLY. Call {@link #getRootDescriptor()} instead. */ - private ElementDescriptor mRootDescriptor; - - private final int mDescriptorId; - - private AndroidEditor mEditor; - - /** - * Constructor for AndroidContentAssist - * @param descriptorId An id for {@link AndroidTargetData#getDescriptorProvider(int)}. - * The Id can be one of {@link AndroidTargetData#DESCRIPTOR_MANIFEST}, - * {@link AndroidTargetData#DESCRIPTOR_LAYOUT}, - * {@link AndroidTargetData#DESCRIPTOR_MENU}, - * or {@link AndroidTargetData#DESCRIPTOR_XML}. - * All other values will throw an {@link IllegalArgumentException} later at runtime. - */ - public AndroidContentAssist(int descriptorId) { - mDescriptorId = descriptorId; - } - - /** - * Returns a list of completion proposals based on the - * specified location within the document that corresponds - * to the current cursor position within the text viewer. - * - * @param viewer the viewer whose document is used to compute the proposals - * @param offset an offset within the document for which completions should be computed - * @return an array of completion proposals or <code>null</code> if no proposals are possible - * - * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int) - */ - public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { - - if (mEditor == null) { - mEditor = getAndroidEditor(viewer); - } - - UiElementNode rootUiNode = mEditor.getUiRootNode(); - - Object[] choices = null; /* An array of ElementDescriptor, or AttributeDescriptor - or String or null */ - String parent = ""; //$NON-NLS-1$ - String wordPrefix = extractElementPrefix(viewer, offset); - char needTag = 0; - boolean isElement = false; - boolean isAttribute = false; - - Node currentNode = getNode(viewer, offset); - if (currentNode == null) - return null; - - // check to see if we can find a UiElementNode matching this XML node - UiElementNode currentUiNode = - rootUiNode == null ? null : rootUiNode.findXmlNode(currentNode); - - if (currentNode.getNodeType() == Node.ELEMENT_NODE) { - parent = currentNode.getNodeName(); - - if (wordPrefix.equals(parent)) { - // We are still editing the element's tag name, not the attributes - // (the element's tag name may not even be complete) - isElement = true; - choices = getChoicesForElement(parent, currentNode); - } else { - // We're not editing the current node name, so we might be editing its - // attributes instead... - isAttribute = true; - AttribInfo info = parseAttributeInfo(viewer, offset); - if (info != null) { - // We're editing attributes in an element node (either the attributes' names - // or their values). - choices = getChoicesForAttribute(parent, currentNode, currentUiNode, info); - - if (info.correctedPrefix != null) { - wordPrefix = info.correctedPrefix; - } - needTag = info.needTag; - } - } - } else if (currentNode.getNodeType() == Node.TEXT_NODE) { - isElement = true; - // Examine the parent of the text node. - choices = getChoicesForTextNode(currentNode); - } - - // Abort if we can't recognize the context or there are no completion choices - if (choices == null || choices.length == 0) return null; - - if (isElement) { - // If we found some suggestions, do we need to add an opening "<" bracket - // for the element? We don't if the cursor is right after "<" or "</". - // Per XML Spec, there's no whitespace between "<" or "</" and the tag name. - int offset2 = offset - wordPrefix.length() - 1; - int c1 = extractChar(viewer, offset2); - if (!((c1 == '<') || (c1 == '/' && extractChar(viewer, offset2 - 1) == '<'))) { - needTag = '<'; - } - } - - // get the selection length - int selectionLength = 0; - ISelection selection = viewer.getSelectionProvider().getSelection(); - if (selection instanceof TextSelection) { - TextSelection textSelection = (TextSelection)selection; - selectionLength = textSelection.getLength(); - } - - return computeProposals(offset, currentNode, choices, wordPrefix, needTag, - isAttribute, selectionLength); - } - - /** - * Returns the namespace prefix matching the Android Resource URI. - * If no such declaration is found, returns the default "android" prefix. - * - * @param node The current node. Must not be null. - * @param nsUri The namespace URI of which the prefix is to be found, - * e.g. {@link SdkConstants#NS_RESOURCES} - * @return The first prefix declared or the default "android" prefix. - */ - private String lookupNamespacePrefix(Node node, String nsUri) { - // Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java - // The following emulates this: - // String prefix = node.lookupPrefix(SdkConstants.NS_RESOURCES); - - if (XmlnsAttributeDescriptor.XMLNS_URI.equals(nsUri)) { - return "xmlns"; //$NON-NLS-1$ - } - - HashSet<String> visited = new HashSet<String>(); - - String prefix = null; - for (; prefix == null && - node != null && - node.getNodeType() == Node.ELEMENT_NODE; - node = node.getParentNode()) { - NamedNodeMap attrs = node.getAttributes(); - for (int n = attrs.getLength() - 1; n >= 0; --n) { - Node attr = attrs.item(n); - if ("xmlns".equals(attr.getPrefix())) { //$NON-NLS-1$ - String uri = attr.getNodeValue(); - if (SdkConstants.NS_RESOURCES.equals(uri)) { - return attr.getLocalName(); - } - visited.add(uri); - } - } - } - - // Use a sensible default prefix if we can't find one. - // We need to make sure the prefix is not one that was declared in the scope - // visited above. - prefix = SdkConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$ - String base = prefix; - for (int i = 1; visited.contains(prefix); i++) { - prefix = base + Integer.toString(i); - } - return prefix; - } - - /** - * Gets the choices when the user is editing the name of an XML element. - * <p/> - * The user is editing the name of an element (the "parent"). - * Find the grand-parent and if one is found, return its children element list. - * The name which is being edited should be one of those. - * <p/> - * Example: <manifest><applic*cursor* => returns the list of all elements that - * can be found under <manifest>, of which <application> is one of the choices. - * - * @return an ElementDescriptor[] or null if no valid element was found. - */ - private Object[] getChoicesForElement(String parent, Node current_node) { - ElementDescriptor grandparent = null; - if (current_node.getParentNode().getNodeType() == Node.ELEMENT_NODE) { - grandparent = getDescriptor(current_node.getParentNode().getNodeName()); - } else if (current_node.getParentNode().getNodeType() == Node.DOCUMENT_NODE) { - grandparent = getRootDescriptor(); - } - if (grandparent != null) { - for (ElementDescriptor e : grandparent.getChildren()) { - if (e.getXmlName().startsWith(parent)) { - return grandparent.getChildren(); - } - } - } - - return null; - } - - /** - * Gets the choices when the user is editing an XML attribute. - * <p/> - * In input, attrInfo contains details on the analyzed context, namely whether the - * user is editing an attribute value (isInValue) or an attribute name. - * <p/> - * In output, attrInfo also contains two possible new values (this is a hack to circumvent - * the lack of out-parameters in Java): - * - AttribInfo.correctedPrefix if the user has been editing an attribute value and it has - * been detected that what the user typed is different from what extractElementPrefix() - * predicted. This happens because extractElementPrefix() stops when a character that - * cannot be an element name appears whereas parseAttributeInfo() uses a grammar more - * lenient as suitable for attribute values. - * - AttribInfo.needTag will be non-zero if we find that the attribute completion proposal - * must be double-quoted. - * @param currentUiNode - * - * @return an AttributeDescriptor[] if the user is editing an attribute name. - * a String[] if the user is editing an attribute value with some known values, - * or null if nothing is known about the context. - */ - private Object[] getChoicesForAttribute(String parent, - Node currentNode, UiElementNode currentUiNode, AttribInfo attrInfo) { - Object[] choices = null; - if (attrInfo.isInValue) { - // Editing an attribute's value... Get the attribute name and then the - // possible choice for the tuple(parent,attribute) - String value = attrInfo.value; - if (value.startsWith("'") || value.startsWith("\"")) { //$NON-NLS-1$ //$NON-NLS-2$ - value = value.substring(1); - // The prefix that was found at the beginning only scan for characters - // valid of tag name. We now know the real prefix for this attribute's - // value, which is needed to generate the completion choices below. - attrInfo.correctedPrefix = value; - } else { - attrInfo.needTag = '"'; - } - - if (currentUiNode != null) { - // look for an UI attribute matching the current attribute name - String attrName = attrInfo.name; - - UiAttributeNode currAttrNode = null; - for (UiAttributeNode attrNode : currentUiNode.getUiAttributes()) { - if (attrNode.getDescriptor().getXmlLocalName().equals(attrName)) { - currAttrNode = attrNode; - break; - } - } - - if (currAttrNode != null) { - choices = currAttrNode.getPossibleValues(); - - if (currAttrNode instanceof UiFlagAttributeNode) { - // A "flag" can consist of several values separated by "or" (|). - // If the correct prefix contains such a pipe character, we change - // it so that only the currently edited value is completed. - int pos = value.indexOf('|'); - if (pos >= 0) { - attrInfo.correctedPrefix = value = value.substring(pos + 1); - attrInfo.needTag = 0; - } - } - } - } - - if (choices == null) { - // fallback on the older descriptor-only based lookup. - - // in order to properly handle the special case of the name attribute in - // the action tag, we need the grandparent of the action node, to know - // what type of actions we need. - // e.g. activity -> intent-filter -> action[@name] - String greatGrandParentName = null; - Node grandParent = currentNode.getParentNode(); - if (grandParent != null) { - Node greatGrandParent = grandParent.getParentNode(); - if (greatGrandParent != null) { - greatGrandParentName = greatGrandParent.getLocalName(); - } - } - - AndroidTargetData data = mEditor.getTargetData(); - if (data != null) { - choices = data.getAttributeValues(parent, attrInfo.name, greatGrandParentName); - } - } - } else { - // Editing an attribute's name... Get attributes valid for the parent node. - if (currentUiNode != null) { - choices = currentUiNode.getAttributeDescriptors(); - } else { - ElementDescriptor parent_desc = getDescriptor(parent); - choices = parent_desc.getAttributes(); - } - } - return choices; - } - - /** - * Gets the choices when the user is editing an XML text node. - * <p/> - * This means the user is editing outside of any XML element or attribute. - * Simply return the list of XML elements that can be present there, based on the - * parent of the current node. - * - * @return An ElementDescriptor[] or null. - */ - private Object[] getChoicesForTextNode(Node currentNode) { - Object[] choices = null; - String parent; - Node parent_node = currentNode.getParentNode(); - if (parent_node.getNodeType() == Node.ELEMENT_NODE) { - // We're editing a text node which parent is an element node. Limit - // content assist to elements valid for the parent. - parent = parent_node.getNodeName(); - ElementDescriptor desc = getDescriptor(parent); - if (desc != null) { - choices = desc.getChildren(); - } - } else if (parent_node.getNodeType() == Node.DOCUMENT_NODE) { - // We're editing a text node at the first level (i.e. root node). - // Limit content assist to the only valid root elements. - choices = getRootDescriptor().getChildren(); - } - return choices; - } - - /** - * Given a list of choices found, generates the proposals to be displayed to the user. - * <p/> - * Choices is an object array. Items of the array can be: - * - ElementDescriptor: a possible element descriptor which XML name should be completed. - * - AttributeDescriptor: a possible attribute descriptor which XML name should be completed. - * - String: string values to display as-is to the user. Typically those are possible - * values for a given attribute. - * - * @return The ICompletionProposal[] to display to the user. - */ - private ICompletionProposal[] computeProposals(int offset, Node currentNode, - Object[] choices, String wordPrefix, char need_tag, - boolean is_attribute, int selectionLength) { - ArrayList<CompletionProposal> proposals = new ArrayList<CompletionProposal>(); - HashMap<String, String> nsUriMap = new HashMap<String, String>(); - - for (Object choice : choices) { - String keyword = null; - String nsPrefix = null; - Image icon = null; - String tooltip = null; - if (choice instanceof ElementDescriptor) { - keyword = ((ElementDescriptor)choice).getXmlName(); - icon = ((ElementDescriptor)choice).getIcon(); - tooltip = DescriptorsUtils.formatTooltip(((ElementDescriptor)choice).getTooltip()); - } else if (choice instanceof TextValueDescriptor) { - continue; // Value nodes are not part of the completion choices - } else if (choice instanceof SeparatorAttributeDescriptor) { - continue; // not real attribute descriptors - } else if (choice instanceof AttributeDescriptor) { - keyword = ((AttributeDescriptor)choice).getXmlLocalName(); - icon = ((AttributeDescriptor)choice).getIcon(); - if (choice instanceof TextAttributeDescriptor) { - tooltip = ((TextAttributeDescriptor) choice).getTooltip(); - } - - String nsUri = ((AttributeDescriptor)choice).getNamespaceUri(); - nsPrefix = nsUriMap.get(nsUri); - if (nsPrefix == null) { - nsPrefix = lookupNamespacePrefix(currentNode, nsUri); - nsUriMap.put(nsUri, nsPrefix); - } - if (nsPrefix != null) { - nsPrefix += ":"; //$NON-NLS-1$ - } - - } else if (choice instanceof String) { - keyword = (String) choice; - } else { - continue; // discard unknown choice - } - - if (keyword.startsWith(wordPrefix) || - (nsPrefix != null && keyword.startsWith(nsPrefix))) { - if (nsPrefix != null) { - keyword = nsPrefix + keyword; - } - String end_tag = ""; //$NON-NLS-1$ - if (need_tag != 0) { - if (need_tag == '"') { - keyword = need_tag + keyword; - end_tag = String.valueOf(need_tag); - } else if (need_tag == '<') { - if (elementCanHaveChildren(choice)) { - end_tag = String.format("></%1$s>", keyword); //$NON-NLS-1$ - keyword = need_tag + keyword; - } else { - keyword = need_tag + keyword; - end_tag = "/>"; //$NON-NLS-1$ - } - } - } - CompletionProposal proposal = new CompletionProposal( - keyword + end_tag, // String replacementString - offset - wordPrefix.length(), // int replacementOffset - wordPrefix.length() + selectionLength, // int replacementLength - keyword.length(), // int cursorPosition (rel. to rplcmntOffset) - icon, // Image image - null, // String displayString - null, // IContextInformation contextInformation - tooltip // String additionalProposalInfo - ); - - proposals.add(proposal); - } - } - - return proposals.toArray(new ICompletionProposal[proposals.size()]); - } - - /** - * Indicates whether this descriptor describes an element that can potentially - * have children (either sub-elements or text value). If an element can have children, - * we want to explicitly write an opening and a separate closing tag. - * <p/> - * Elements can have children if the descriptor has children element descriptors - * or if one of the attributes is a TextValueDescriptor. - * - * @param descriptor An ElementDescriptor or an AttributeDescriptor - * @return True if the descriptor is an ElementDescriptor that can have children or a text value - */ - private boolean elementCanHaveChildren(Object descriptor) { - if (descriptor instanceof ElementDescriptor) { - ElementDescriptor desc = (ElementDescriptor) descriptor; - if (desc.hasChildren()) { - return true; - } - for (AttributeDescriptor attr_desc : desc.getAttributes()) { - if (attr_desc instanceof TextValueDescriptor) { - return true; - } - } - } - return false; - } - - /** - * Returns the element descriptor matching a given XML node name or null if it can't be - * found. - * <p/> - * This is simplistic; ideally we should consider the parent's chain to make sure we - * can differentiate between different hierarchy trees. Right now the first match found - * is returned. - */ - private ElementDescriptor getDescriptor(String nodeName) { - return getRootDescriptor().findChildrenDescriptor(nodeName, true /* recursive */); - } - - public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { - return null; - } - - /** - * Returns the characters which when entered by the user should - * automatically trigger the presentation of possible completions. - * - * In our case, we auto-activate on opening tags and attributes namespace. - * - * @return the auto activation characters for completion proposal or <code>null</code> - * if no auto activation is desired - */ - public char[] getCompletionProposalAutoActivationCharacters() { - return new char[]{ '<', ':', '=' }; - } - - public char[] getContextInformationAutoActivationCharacters() { - return null; - } - - public IContextInformationValidator getContextInformationValidator() { - return null; - } - - public String getErrorMessage() { - return null; - } - - /** - * Heuristically extracts the prefix used for determining template relevance - * from the viewer's document. The default implementation returns the String from - * offset backwards that forms a potential XML element name. - * - * Code extracted from org.eclipse.jface.text.templatesTemplateCompletionProcessor - * and adapted to our needs. - * - * @param viewer the viewer - * @param offset offset into document - * @return the prefix to consider - */ - protected String extractElementPrefix(ITextViewer viewer, int offset) { - int i = offset; - IDocument document = viewer.getDocument(); - if (i > document.getLength()) return ""; //$NON-NLS-1$ - - try { - for (; i > 0; --i) { - char ch = document.getChar(i - 1); - // accepted characters are a-z and : (for attributes' namespace) - if (ch != ':' && (ch < 'a' || ch > 'z')) break; - } - - return document.get(i, offset - i); - } catch (BadLocationException e) { - return ""; //$NON-NLS-1$ - } - } - - /** - * Extracts the character at the given offset. - * Returns 0 if the offset is invalid. - */ - protected char extractChar(ITextViewer viewer, int offset) { - IDocument document = viewer.getDocument(); - if (offset > document.getLength()) return 0; - - try { - return document.getChar(offset); - } catch (BadLocationException e) { - return 0; - } - } - - /** - * Information about the current edit of an attribute as reported by parseAttributeInfo. - */ - private class AttribInfo { - /** True if the cursor is located in an attribute's value, false if in an attribute name */ - public boolean isInValue = false; - /** The attribute name. Null when not set. */ - public String name = null; - /** The attribute value. Null when not set. The value *may* start with a quote - * (' or "), in which case we know we don't need to quote the string for the user */ - public String value = null; - /** String typed by the user so far (i.e. right before requesting code completion), - * which will be corrected if we find a possible completion for an attribute value. - * See the long comment in getChoicesForAttribute(). */ - public String correctedPrefix = null; - /** Non-zero if an attribute value need a start/end tag (i.e. quotes or brackets) */ - public char needTag = 0; - } - - - /** - * Try to guess if the cursor is editing an element's name or an attribute following an - * element. If it's an attribute, try to find if an attribute name is being defined or - * its value. - * <br/> - * This is currently *only* called when we know the cursor is after a complete element - * tag name, so it should never return null. - * <br/> - * Reference for XML syntax: http://www.w3.org/TR/2006/REC-xml-20060816/#sec-starttags - * <br/> - * @return An AttribInfo describing which attribute is being edited or null if the cursor is - * not editing an attribute (in which case it must be an element's name). - */ - private AttribInfo parseAttributeInfo(ITextViewer viewer, int offset) { - AttribInfo info = new AttribInfo(); - - IDocument document = viewer.getDocument(); - int n = document.getLength(); - if (offset <= n) { - try { - n = offset; - for (;offset > 0; --offset) { - char ch = document.getChar(offset - 1); - if (ch == '<') break; - } - - // text will contain the full string of the current element, - // i.e. whatever is after the "<" to the current cursor - String text = document.get(offset, n - offset); - - // Normalize whitespace to single spaces - text = sWhitespace.matcher(text).replaceAll(" "); //$NON-NLS-1$ - - // Remove the leading element name. By spec, it must be after the < without - // any whitespace. If there's nothing left, no attribute has been defined yet. - // Be sure to keep any whitespace after the initial word if any, as it matters. - text = sFirstElementWord.matcher(text).replaceFirst(""); //$NON-NLS-1$ - - // There MUST be space after the element name. If not, the cursor is still - // defining the element name. - if (!text.startsWith(" ")) { //$NON-NLS-1$ - return null; - } - - // Remove full attributes: - // Syntax: - // name = "..." quoted string with all but < and " - // or: - // name = '...' quoted string with all but < and ' - String temp; - do { - temp = text; - text = sFirstAttribute.matcher(temp).replaceFirst(""); //$NON-NLS-1$ - } while(!temp.equals(text)); - - // Now we're left with 3 cases: - // - nothing: either there is no attribute definition or the cursor located after - // a completed attribute definition. - // - a string with no =: the user is writing an attribute name. This case can be - // merged with the previous one. - // - string with an = sign, optionally followed by a quote (' or "): the user is - // writing the value of the attribute. - int pos_equal = text.indexOf('='); - if (pos_equal == -1) { - info.isInValue = false; - info.name = text.trim(); - } else { - info.isInValue = true; - info.name = text.substring(0, pos_equal).trim(); - info.value = text.substring(pos_equal + 1).trim(); - } - return info; - } catch (BadLocationException e) { - // pass - } - } - - return null; - } - - - /** - * Returns the XML DOM node corresponding to the given offset of the given document. - */ - protected Node getNode(ITextViewer viewer, int offset) { - Node node = null; - try { - IModelManager mm = StructuredModelManager.getModelManager(); - if (mm != null) { - IStructuredModel model = mm.getExistingModelForRead(viewer.getDocument()); - if (model != null) { - for(; offset >= 0 && node == null; --offset) { - node = (Node) model.getIndexedRegion(offset); - } - } - } - } catch (Exception e) { - // Ignore exceptions. - } - - return node; - } - - /** - * Computes (if needed) and returns the root descriptor. - */ - private ElementDescriptor getRootDescriptor() { - if (mRootDescriptor == null) { - AndroidTargetData data = mEditor.getTargetData(); - if (data != null) { - IDescriptorProvider descriptorProvider = data.getDescriptorProvider(mDescriptorId); - - if (descriptorProvider != null) { - mRootDescriptor = new ElementDescriptor("", - descriptorProvider.getRootElementDescriptors()); - } - } - } - - return mRootDescriptor; - } - - /** - * Returns the active {@link AndroidEditor} matching this source viewer. - */ - private AndroidEditor getAndroidEditor(ITextViewer viewer) { - IWorkbenchWindow wwin = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (wwin != null) { - IWorkbenchPage page = wwin.getActivePage(); - if (page != null) { - IEditorPart editor = page.getActiveEditor(); - if (editor instanceof AndroidEditor) { - ISourceViewer ssviewer = ((AndroidEditor) editor).getStructuredSourceViewer(); - if (ssviewer == viewer) { - return (AndroidEditor) editor; - } - } - } - } - - return null; - } - - - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java deleted file mode 100644 index dca7db0..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Copyright (C) 2007 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.editors; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceChangeEvent; -import org.eclipse.core.resources.IResourceChangeListener; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.text.source.ISourceViewer; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IEditorSite; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.browser.IWorkbenchBrowserSupport; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.IFormPage; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.events.IHyperlinkListener; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport; -import org.eclipse.ui.part.FileEditorInput; -import org.eclipse.ui.part.MultiPageEditorPart; -import org.eclipse.ui.part.WorkbenchPart; -import org.eclipse.wst.sse.core.StructuredModelManager; -import org.eclipse.wst.sse.core.internal.provisional.IModelManager; -import org.eclipse.wst.sse.core.internal.provisional.IModelStateListener; -import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; -import org.eclipse.wst.sse.ui.StructuredTextEditor; -import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; -import org.w3c.dom.Document; - -import java.net.MalformedURLException; -import java.net.URL; - -/** - * Multi-page form editor for Android XML files. - * <p/> - * It is designed to work with a {@link StructuredTextEditor} that will display an XML file. - * <br/> - * Derived classes must implement createFormPages to create the forms before the - * source editor. This can be a no-op if desired. - */ -public abstract class AndroidEditor extends FormEditor implements IResourceChangeListener { - - /** Preference name for the current page of this file */ - private static final String PREF_CURRENT_PAGE = "_current_page"; - - /** Id string used to create the Android SDK browser */ - private static String BROWSER_ID = "android"; // $NON-NLS-1$ - - /** Page id of the XML source editor, used for switching tabs programmatically */ - public final static String TEXT_EDITOR_ID = "editor_part"; //$NON-NLS-1$ - - /** Width hint for text fields. Helps the grid layout resize properly on smaller screens */ - public static final int TEXT_WIDTH_HINT = 50; - - /** Page index of the text editor (always the last page) */ - private int mTextPageIndex; - /** The text editor */ - private StructuredTextEditor mTextEditor; - /** Listener for the XML model from the StructuredEditor */ - private XmlModelStateListener mXmlModelStateListener; - /** Listener to update the root node if the resource framework changes */ - private Runnable mResourceRefreshListener; - - /** - * Creates a form editor. - */ - public AndroidEditor() { - super(); - ResourcesPlugin.getWorkspace().addResourceChangeListener(this); - - mResourceRefreshListener = new Runnable() { - public void run() { - commitPages(false /* onSave */); - - // recreate the ui root node always - initUiRootNode(true /*force*/); - } - }; - AdtPlugin.getDefault().addResourceChangedListener(mResourceRefreshListener); - } - - // ---- Abstract Methods ---- - - /** - * Returns the root node of the UI element hierarchy manipulated by the current - * UI node editor. - */ - abstract public UiElementNode getUiRootNode(); - - /** - * Creates the various form pages. - * <p/> - * Derived classes must implement this to add their own specific tabs. - */ - abstract protected void createFormPages(); - - /** - * Creates the initial UI Root Node, including the known mandatory elements. - * @param force if true, a new UiManifestNode is recreated even if it already exists. - */ - abstract protected void initUiRootNode(boolean force); - - /** - * Subclasses should override this method to process the new XML Model, which XML - * root node is given. - * - * The base implementation is empty. - * - * @param xml_doc The XML document, if available, or null if none exists. - */ - protected void xmlModelChanged(Document xml_doc) { - // pass - } - - // ---- Base Class Overrides, Interfaces Implemented ---- - - /** - * Creates the pages of the multi-page editor. - */ - @Override - protected void addPages() { - createAndroidPages(); - selectDefaultPage(null /* defaultPageId */); - } - - /** - * Creates the page for the Android Editors - */ - protected void createAndroidPages() { - createFormPages(); - createTextEditor(); - - createUndoRedoActions(); - } - - /** - * Creates undo redo actions for the editor site (so that it works for any page of this - * multi-page editor) by re-using the actions defined by the {@link StructuredTextEditor} - * (aka the XML text editor.) - */ - private void createUndoRedoActions() { - IActionBars bars = getEditorSite().getActionBars(); - if (bars != null) { - IAction action = mTextEditor.getAction(ActionFactory.UNDO.getId()); - bars.setGlobalActionHandler(ActionFactory.UNDO.getId(), action); - - action = mTextEditor.getAction(ActionFactory.REDO.getId()); - bars.setGlobalActionHandler(ActionFactory.REDO.getId(), action); - - bars.updateActionBars(); - } - } - - /** - * Selects the default active page. - * @param defaultPageId the id of the page to show. If <code>null</code> the editor attempts to - * find the default page in the properties of the {@link IResource} object being edited. - */ - protected void selectDefaultPage(String defaultPageId) { - if (defaultPageId == null) { - if (getEditorInput() instanceof IFileEditorInput) { - IFile file = ((IFileEditorInput) getEditorInput()).getFile(); - - QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, - getClass().getSimpleName() + PREF_CURRENT_PAGE); - String pageId; - try { - pageId = file.getPersistentProperty(qname); - if (pageId != null) { - defaultPageId = pageId; - } - } catch (CoreException e) { - // ignored - } - } - } - - if (defaultPageId != null) { - try { - setActivePage(Integer.parseInt(defaultPageId)); - } catch (Exception e) { - // We can get NumberFormatException from parseInt but also - // AssertionError from setActivePage when the index is out of bounds. - // Generally speaking we just want to ignore any exception and fall back on the - // first page rather than crash the editor load. Logging the error is enough. - AdtPlugin.log(e, "Selecting page '%s' in AndroidEditor failed", defaultPageId); - } - } - } - - /** - * Removes all the pages from the editor. - */ - protected void removePages() { - int count = getPageCount(); - for (int i = count - 1 ; i >= 0 ; i--) { - removePage(i); - } - } - - /** - * Overrides the parent's setActivePage to be able to switch to the xml editor. - * - * If the special pageId TEXT_EDITOR_ID is given, switches to the mTextPageIndex page. - * This is needed because the editor doesn't actually derive from IFormPage and thus - * doesn't have the get-by-page-id method. In this case, the method returns null since - * IEditorPart does not implement IFormPage. - */ - @Override - public IFormPage setActivePage(String pageId) { - if (pageId.equals(TEXT_EDITOR_ID)) { - super.setActivePage(mTextPageIndex); - return null; - } else { - return super.setActivePage(pageId); - } - } - - - /** - * Notifies this multi-page editor that the page with the given id has been - * activated. This method is called when the user selects a different tab. - * - * @see MultiPageEditorPart#pageChange(int) - */ - @Override - protected void pageChange(int newPageIndex) { - super.pageChange(newPageIndex); - - if (getEditorInput() instanceof IFileEditorInput) { - IFile file = ((IFileEditorInput) getEditorInput()).getFile(); - - QualifiedName qname = new QualifiedName(AdtPlugin.PLUGIN_ID, - getClass().getSimpleName() + PREF_CURRENT_PAGE); - try { - file.setPersistentProperty(qname, Integer.toString(newPageIndex)); - } catch (CoreException e) { - // ignore - } - } - } - - /** - * Notifies this listener that some resource changes - * are happening, or have already happened. - * - * Closes all project files on project close. - * @see IResourceChangeListener - */ - public void resourceChanged(final IResourceChangeEvent event) { - if (event.getType() == IResourceChangeEvent.PRE_CLOSE) { - Display.getDefault().asyncExec(new Runnable() { - public void run() { - IWorkbenchPage[] pages = getSite().getWorkbenchWindow() - .getPages(); - for (int i = 0; i < pages.length; i++) { - if (((FileEditorInput)mTextEditor.getEditorInput()) - .getFile().getProject().equals( - event.getResource())) { - IEditorPart editorPart = pages[i].findEditor(mTextEditor - .getEditorInput()); - pages[i].closeEditor(editorPart, true); - } - } - } - }); - } - } - - /** - * Initializes the editor part with a site and input. - * <p/> - * Checks that the input is an instance of {@link IFileEditorInput}. - * - * @see FormEditor - */ - @Override - public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException { - if (!(editorInput instanceof IFileEditorInput)) - throw new PartInitException("Invalid Input: Must be IFileEditorInput"); - super.init(site, editorInput); - } - - /** - * Removes attached listeners. - * - * @see WorkbenchPart - */ - @Override - public void dispose() { - IStructuredModel xml_model = getModelForRead(); - if (xml_model != null) { - try { - if (mXmlModelStateListener != null) { - xml_model.removeModelStateListener(mXmlModelStateListener); - } - - } finally { - xml_model.releaseFromRead(); - } - } - ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); - - if (mResourceRefreshListener != null) { - AdtPlugin.getDefault().removeResourceChangedListener(mResourceRefreshListener); - mResourceRefreshListener = null; - } - - super.dispose(); - } - - /** - * Commit all dirty pages then saves the contents of the text editor. - * <p/> - * This works by committing all data to the XML model and then - * asking the Structured XML Editor to save the XML. - * - * @see IEditorPart - */ - @Override - public void doSave(IProgressMonitor monitor) { - commitPages(true /* onSave */); - - // The actual "save" operation is done by the Structured XML Editor - getEditor(mTextPageIndex).doSave(monitor); - } - - /* (non-Javadoc) - * Saves the contents of this editor to another object. - * <p> - * Subclasses must override this method to implement the open-save-close lifecycle - * for an editor. For greater details, see <code>IEditorPart</code> - * </p> - * - * @see IEditorPart - */ - @Override - public void doSaveAs() { - commitPages(true /* onSave */); - - IEditorPart editor = getEditor(mTextPageIndex); - editor.doSaveAs(); - setPageText(mTextPageIndex, editor.getTitle()); - setInput(editor.getEditorInput()); - } - - /** - * Commits all dirty pages in the editor. This method should - * be called as a first step of a 'save' operation. - * <p/> - * This is the same implementation as in {@link FormEditor} - * except it fixes two bugs: a cast to IFormPage is done - * from page.get(i) <em>before</em> being tested with instanceof. - * Another bug is that the last page might be a null pointer. - * <p/> - * The incorrect casting makes the original implementation crash due - * to our {@link StructuredTextEditor} not being an {@link IFormPage} - * so we have to override and duplicate to fix it. - * - * @param onSave <code>true</code> if commit is performed as part - * of the 'save' operation, <code>false</code> otherwise. - * @since 3.3 - */ - @Override - public void commitPages(boolean onSave) { - if (pages != null) { - for (int i = 0; i < pages.size(); i++) { - Object page = pages.get(i); - if (page != null && page instanceof IFormPage) { - IFormPage form_page = (IFormPage) page; - IManagedForm managed_form = form_page.getManagedForm(); - if (managed_form != null && managed_form.isDirty()) { - managed_form.commit(onSave); - } - } - } - } - } - - /* (non-Javadoc) - * Returns whether the "save as" operation is supported by this editor. - * <p> - * Subclasses must override this method to implement the open-save-close lifecycle - * for an editor. For greater details, see <code>IEditorPart</code> - * </p> - * - * @see IEditorPart - */ - @Override - public boolean isSaveAsAllowed() { - return false; - } - - // ---- Local methods ---- - - - /** - * Helper method that creates a new hyper-link Listener. - * Used by derived classes which need active links in {@link FormText}. - * <p/> - * This link listener handles two kinds of URLs: - * <ul> - * <li> Links starting with "http" are simply sent to a local browser. - * <li> Links starting with "file:/" are simply sent to a local browser. - * <li> Links starting with "page:" are expected to be an editor page id to switch to. - * <li> Other links are ignored. - * </ul> - * - * @return A new hyper-link listener for FormText to use. - */ - public final IHyperlinkListener createHyperlinkListener() { - return new HyperlinkAdapter() { - /** - * Switch to the page corresponding to the link that has just been clicked. - * For this purpose, the HREF of the <a> tags above is the page ID to switch to. - */ - @Override - public void linkActivated(HyperlinkEvent e) { - super.linkActivated(e); - String link = e.data.toString(); - if (link.startsWith("http") || //$NON-NLS-1$ - link.startsWith("file:/")) { //$NON-NLS-1$ - openLinkInBrowser(link); - } else if (link.startsWith("page:")) { //$NON-NLS-1$ - // Switch to an internal page - setActivePage(link.substring(5 /* strlen("page:") */)); - } - } - }; - } - - /** - * Open the http link into a browser - * - * @param link The URL to open in a browser - */ - private void openLinkInBrowser(String link) { - try { - IWorkbenchBrowserSupport wbs = WorkbenchBrowserSupport.getInstance(); - wbs.createBrowser(BROWSER_ID).openURL(new URL(link)); - } catch (PartInitException e1) { - // pass - } catch (MalformedURLException e1) { - // pass - } - } - - /** - * Creates the XML source editor. - * <p/> - * Memorizes the index page of the source editor (it's always the last page, but the number - * of pages before can change.) - * <br/> - * Retrieves the underlying XML model from the StructuredEditor and attaches a listener to it. - * Finally triggers modelChanged() on the model listener -- derived classes can use this - * to initialize the model the first time. - * <p/> - * Called only once <em>after</em> createFormPages. - */ - private void createTextEditor() { - try { - mTextEditor = new StructuredTextEditor(); - int index = addPage(mTextEditor, getEditorInput()); - mTextPageIndex = index; - setPageText(index, mTextEditor.getTitle()); - - if (!(mTextEditor.getTextViewer().getDocument() instanceof IStructuredDocument)) { - Status status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - "Error opening the Android XML editor. Is the document an XML file?"); - throw new RuntimeException("Android XML Editor Error", new CoreException(status)); - } - - IStructuredModel xml_model = getModelForRead(); - if (xml_model != null) { - try { - mXmlModelStateListener = new XmlModelStateListener(); - xml_model.addModelStateListener(mXmlModelStateListener); - mXmlModelStateListener.modelChanged(xml_model); - } catch (Exception e) { - AdtPlugin.log(e, "Error while loading editor"); //$NON-NLS-1$ - } finally { - xml_model.releaseFromRead(); - } - } - } catch (PartInitException e) { - ErrorDialog.openError(getSite().getShell(), - "Android XML Editor Error", null, e.getStatus()); - } - } - - /** - * Returns the ISourceViewer associated with the Structured Text editor. - */ - public final ISourceViewer getStructuredSourceViewer() { - if (mTextEditor != null) { - // We can't access mEditor.getSourceViewer() because it is protected, - // however getTextViewer simply returns the SourceViewer casted, so we - // can use it instead. - return mTextEditor.getTextViewer(); - } - return null; - } - - /** - * Returns the {@link IStructuredDocument} used by the StructuredTextEditor (aka Source - * Editor) or null if not available. - */ - public final IStructuredDocument getStructuredDocument() { - if (mTextEditor != null && mTextEditor.getTextViewer() != null) { - return (IStructuredDocument) mTextEditor.getTextViewer().getDocument(); - } - return null; - } - - /** - * Returns a version of the model that has been shared for read. - * <p/> - * Callers <em>must</em> call model.releaseFromRead() when done, typically - * in a try..finally clause. - * - * @return The model for the XML document or null if cannot be obtained from the editor - */ - public final IStructuredModel getModelForRead() { - IStructuredDocument document = getStructuredDocument(); - if (document != null) { - IModelManager mm = StructuredModelManager.getModelManager(); - if (mm != null) { - return mm.getModelForRead(document); - } - } - return null; - } - - /** - * Returns a version of the model that has been shared for edit. - * <p/> - * Callers <em>must</em> call model.releaseFromEdit() when done, typically - * in a try..finally clause. - * - * @return The model for the XML document or null if cannot be obtained from the editor - */ - public final IStructuredModel getModelForEdit() { - IStructuredDocument document = getStructuredDocument(); - if (document != null) { - IModelManager mm = StructuredModelManager.getModelManager(); - if (mm != null) { - return mm.getModelForEdit(document); - } - } - return null; - } - - /** - * Helper class to perform edits on the XML model whilst making sure the - * model has been prepared to be changed. - * <p/> - * It first gets a model for edition using {@link #getModelForEdit()}, - * then calls {@link IStructuredModel#aboutToChangeModel()}, - * then performs the requested action - * and finally calls {@link IStructuredModel#changedModel()} - * and {@link IStructuredModel#releaseFromEdit()}. - * <p/> - * The method is synchronous. As soon as the {@link IStructuredModel#changedModel()} method - * is called, XML model listeners will be triggered. - * - * @param edit_action Something that will change the XML. - */ - public final void editXmlModel(Runnable edit_action) { - IStructuredModel model = getModelForEdit(); - try { - model.aboutToChangeModel(); - edit_action.run(); - } finally { - // Notify the model we're done modifying it. This must *always* be executed. - model.changedModel(); - model.releaseFromEdit(); - } - } - - /** - * Starts an "undo recording" session. This is managed by the underlying undo manager - * associated to the structured XML model. - * <p/> - * There <em>must</em> be a corresponding call to {@link #endUndoRecording()}. - * <p/> - * beginUndoRecording/endUndoRecording calls can be nested (inner calls are ignored, only one - * undo operation is recorded.) - * - * @param label The label for the undo operation. Can be null but we should really try to put - * something meaningful if possible. - * @return True if the undo recording actually started, false if any kind of error occured. - * {@link #endUndoRecording()} should only be called if True is returned. - */ - private final boolean beginUndoRecording(String label) { - IStructuredDocument document = getStructuredDocument(); - if (document != null) { - IModelManager mm = StructuredModelManager.getModelManager(); - if (mm != null) { - IStructuredModel model = mm.getModelForEdit(document); - if (model != null) { - model.beginRecording(this, label); - return true; - } - } - } - return false; - } - - /** - * Ends an "undo recording" session. - * <p/> - * This is the counterpart call to {@link #beginUndoRecording(String)} and should only be - * used if the initial call returned true. - */ - private final void endUndoRecording() { - IStructuredDocument document = getStructuredDocument(); - if (document != null) { - IModelManager mm = StructuredModelManager.getModelManager(); - if (mm != null) { - IStructuredModel model = mm.getModelForEdit(document); - if (model != null) { - model.endRecording(this); - } - } - } - } - - /** - * Creates an "undo recording" session by calling the undoableAction runnable - * using {@link #beginUndoRecording(String)} and {@link #endUndoRecording()}. - * <p> - * You can nest several calls to {@link #wrapUndoRecording(String, Runnable)}, only one - * recording session will be created. - * - * @param label The label for the undo operation. Can be null. Ideally we should really try - * to put something meaningful if possible. - */ - public void wrapUndoRecording(String label, Runnable undoableAction) { - boolean recording = false; - try { - recording = beginUndoRecording(label); - undoableAction.run(); - } finally { - if (recording) { - endUndoRecording(); - } - } - } - - /** - * Returns the XML {@link Document} or null if we can't get it - */ - protected final Document getXmlDocument(IStructuredModel model) { - if (model == null) { - AdtPlugin.log(IStatus.WARNING, "Android Editor: No XML model for root node."); //$NON-NLS-1$ - return null; - } - - if (model instanceof IDOMModel) { - IDOMModel dom_model = (IDOMModel) model; - return dom_model.getDocument(); - } - return null; - } - - /** - * Returns the {@link IProject} for the edited file. - */ - public IProject getProject() { - if (mTextEditor != null) { - IEditorInput input = mTextEditor.getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - IFile inputFile = fileInput.getFile(); - - if (inputFile != null) { - return inputFile.getProject(); - } - } - } - - return null; - } - - /** - * Returns the {@link AndroidTargetData} for the edited file. - */ - public AndroidTargetData getTargetData() { - IProject project = getProject(); - if (project != null) { - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - IAndroidTarget target = currentSdk.getTarget(project); - - if (target != null) { - return currentSdk.getTargetData(target); - } - } - } - - return null; - } - - - /** - * Listen to changes in the underlying XML model in the structured editor. - */ - private class XmlModelStateListener implements IModelStateListener { - - /** - * A model is about to be changed. This typically is initiated by one - * client of the model, to signal a large change and/or a change to the - * model's ID or base Location. A typical use might be if a client might - * want to suspend processing until all changes have been made. - * <p/> - * This AndroidEditor implementation of IModelChangedListener is empty. - */ - public void modelAboutToBeChanged(IStructuredModel model) { - // pass - } - - /** - * Signals that the changes foretold by modelAboutToBeChanged have been - * made. A typical use might be to refresh, or to resume processing that - * was suspended as a result of modelAboutToBeChanged. - * <p/> - * This AndroidEditor implementation calls the xmlModelChanged callback. - */ - public void modelChanged(IStructuredModel model) { - xmlModelChanged(getXmlDocument(model)); - } - - /** - * Notifies that a model's dirty state has changed, and passes that state - * in isDirty. A model becomes dirty when any change is made, and becomes - * not-dirty when the model is saved. - * <p/> - * This AndroidEditor implementation of IModelChangedListener is empty. - */ - public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) { - // pass - } - - /** - * A modelDeleted means the underlying resource has been deleted. The - * model itself is not removed from model management until all have - * released it. Note: baseLocation is not (necessarily) changed in this - * event, but may not be accurate. - * <p/> - * This AndroidEditor implementation of IModelChangedListener is empty. - */ - public void modelResourceDeleted(IStructuredModel model) { - // pass - } - - /** - * A model has been renamed or copied (as in saveAs..). In the renamed - * case, the two paramenters are the same instance, and only contain the - * new info for id and base location. - * <p/> - * This AndroidEditor implementation of IModelChangedListener is empty. - */ - public void modelResourceMoved(IStructuredModel oldModel, IStructuredModel newModel) { - // pass - } - - /** - * This AndroidEditor implementation of IModelChangedListener is empty. - */ - public void modelAboutToBeReinitialized(IStructuredModel structuredModel) { - // pass - } - - /** - * This AndroidEditor implementation of IModelChangedListener is empty. - */ - public void modelReinitialized(IStructuredModel structuredModel) { - // pass - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidSourceViewerConfig.java deleted file mode 100644 index ab17bef..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidSourceViewerConfig.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2007 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.editors; - - -import org.eclipse.jface.text.IAutoEditStrategy; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.ITextHover; -import org.eclipse.jface.text.contentassist.IContentAssistProcessor; -import org.eclipse.jface.text.contentassist.IContentAssistant; -import org.eclipse.jface.text.formatter.IContentFormatter; -import org.eclipse.jface.text.source.ISourceViewer; -import org.eclipse.jface.viewers.IInputProvider; -import org.eclipse.wst.sse.core.text.IStructuredPartitions; -import org.eclipse.wst.xml.core.text.IXMLPartitions; -import org.eclipse.wst.xml.ui.StructuredTextViewerConfigurationXML; - -import java.util.ArrayList; - -/** - * Base Source Viewer Configuration for Android resources. - */ -public class AndroidSourceViewerConfig extends StructuredTextViewerConfigurationXML { - - /** Content Assist Processor to use for all handled partitions. */ - private IContentAssistProcessor mProcessor; - - public AndroidSourceViewerConfig(IContentAssistProcessor processor) { - super(); - mProcessor = processor; - } - - @Override - public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { - return super.getContentAssistant(sourceViewer); - } - - /** - * Returns the content assist processors that will be used for content - * assist in the given source viewer and for the given partition type. - * - * @param sourceViewer the source viewer to be configured by this - * configuration - * @param partitionType the partition type for which the content assist - * processors are applicable - * @return IContentAssistProcessors or null if should not be supported - */ - @Override - protected IContentAssistProcessor[] getContentAssistProcessors( - ISourceViewer sourceViewer, String partitionType) { - ArrayList<IContentAssistProcessor> processors = new ArrayList<IContentAssistProcessor>(); - if (partitionType == IStructuredPartitions.UNKNOWN_PARTITION || - partitionType == IStructuredPartitions.DEFAULT_PARTITION || - partitionType == IXMLPartitions.XML_DEFAULT) { - if (sourceViewer instanceof IInputProvider) { - IInputProvider input = (IInputProvider) sourceViewer; - Object a = input.getInput(); - if (a != null) - a.toString(); - } - - IDocument doc = sourceViewer.getDocument(); - if (doc != null) - doc.toString(); - - processors.add(mProcessor); - } - - IContentAssistProcessor[] others = super.getContentAssistProcessors(sourceViewer, - partitionType); - if (others != null && others.length > 0) { - for (IContentAssistProcessor p : others) { - processors.add(p); - } - } - - if (processors.size() > 0) { - return processors.toArray(new IContentAssistProcessor[processors.size()]); - } else { - return null; - } - } - - @Override - public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { - // TODO text hover for android xml - return super.getTextHover(sourceViewer, contentType); - } - - @Override - public IAutoEditStrategy[] getAutoEditStrategies( - ISourceViewer sourceViewer, String contentType) { - // TODO auto edit strategies for android xml - return super.getAutoEditStrategies(sourceViewer, contentType); - } - - @Override - public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) { - // TODO content formatter for android xml - return super.getContentFormatter(sourceViewer); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/FirstElementParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/FirstElementParser.java deleted file mode 100644 index bb0996b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/FirstElementParser.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2008 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.editors; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Quickly parses a (potential) XML file to extract its first element (i.e. the root element) - * and namespace, if any. - * <p/> - * This is used to determine if a file is an XML document that the XmlEditor can process. - * <p/> - * TODO use this to remove the hardcoded "android" namespace prefix limitation. - */ -public final class FirstElementParser { - - private static SAXParserFactory sSaxfactory; - - /** - * Result from the XML parsing. <br/> - * Contains the name of the root XML element. <br/> - * If an XMLNS URI was specified and found, the XMLNS prefix is recorded. Otherwise it is null. - */ - public static final class Result { - private String mElement; - private String mXmlnsPrefix; - private String mXmlnsUri; - - public String getElement() { - return mElement; - } - - public String getXmlnsPrefix() { - return mXmlnsPrefix; - } - - public String getXmlnsUri() { - return mXmlnsUri; - } - - void setElement(String element) { - mElement = element; - } - - void setXmlnsPrefix(String xmlnsPrefix) { - mXmlnsPrefix = xmlnsPrefix; - } - - void setXmlnsUri(String xmlnsUri) { - mXmlnsUri = xmlnsUri; - } - } - - private static class ResultFoundException extends SAXException { } - - /** - * Parses the given filename. - * - * @param osFilename The file to parse. - * @param xmlnsUri An optional URL of which we want to know the prefix. - * @return The element details found or null if not found. - */ - public static Result parse(String osFilename, String xmlnsUri) { - if (sSaxfactory == null) { - // TODO just create a single factory in CommonPlugin and reuse it - sSaxfactory = SAXParserFactory.newInstance(); - sSaxfactory.setNamespaceAware(true); - } - - Result result = new Result(); - if (xmlnsUri != null && xmlnsUri.length() > 0) { - result.setXmlnsUri(xmlnsUri); - } - - try { - SAXParser parser = sSaxfactory.newSAXParser(); - XmlHandler handler = new XmlHandler(result); - parser.parse(new InputSource(new FileReader(osFilename)), handler); - - } catch(ResultFoundException e) { - // XML handling was aborted because the required element was found. - // Simply return the result. - return result; - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (FileNotFoundException e) { - } catch (IOException e) { - } - - return null; - } - - /** - * Private constructor. Use the static parse() method instead. - */ - private FirstElementParser() { - // pass - } - - /** - * A specialized SAX handler that captures the arguments of the very first element - * (i.e. the root element) - */ - private static class XmlHandler extends DefaultHandler { - private final Result mResult; - - public XmlHandler(Result result) { - mResult = result; - } - - /** - * Processes a namespace prefix mapping. - * I.e. for xmlns:android="some-uri", this received prefix="android" and uri="some-uri". - * <p/> - * The prefix is recorded in the result structure if the URI is the one searched for. - * <p/> - * This event happens <em>before</em> the corresponding startElement event. - */ - @Override - public void startPrefixMapping(String prefix, String uri) { - if (uri.equals(mResult.getXmlnsUri())) { - mResult.setXmlnsPrefix(prefix); - } - } - - /** - * Processes a new element start. - * <p/> - * This simply records the element name and abort processing by throwing an exception. - */ - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) - throws SAXException { - mResult.setElement(localName); - throw new ResultFoundException(); - } - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java deleted file mode 100644 index 2c24772..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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.editors; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.sdklib.SdkConstants; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Display; - -import java.util.HashMap; - -/** - * Factory to generate icons for Android Editors. - * <p/> - * Icons are kept here and reused. - */ -public class IconFactory { - - public static final int COLOR_RED = SWT.COLOR_DARK_RED; - public static final int COLOR_GREEN = SWT.COLOR_DARK_GREEN; - public static final int COLOR_BLUE = SWT.COLOR_DARK_BLUE; - public static final int COLOR_DEFAULT = SWT.COLOR_BLACK; - - public static final int SHAPE_CIRCLE = 'C'; - public static final int SHAPE_RECT = 'R'; - public static final int SHAPE_DEFAULT = SHAPE_CIRCLE; - - private static IconFactory sInstance; - - private HashMap<String, Image> mIconMap = new HashMap<String, Image>(); - private HashMap<String, ImageDescriptor> mImageDescMap = new HashMap<String, ImageDescriptor>(); - - private IconFactory() { - } - - public static synchronized IconFactory getInstance() { - if (sInstance == null) { - sInstance = new IconFactory(); - } - return sInstance; - } - - public void Dispose() { - // Dispose icons - for (Image icon : mIconMap.values()) { - // The map can contain null values - if (icon != null) { - icon.dispose(); - } - } - mIconMap.clear(); - } - - /** - * Returns an Image for a given icon name. - * <p/> - * Callers should not dispose it. - * - * @param osName The leaf name, without the extension, of an existing icon in the - * editor's "icons" directory. If it doesn't exists, a default icon will be - * generated automatically based on the name. - */ - public Image getIcon(String osName) { - return getIcon(osName, COLOR_DEFAULT, SHAPE_DEFAULT); - } - - /** - * Returns an Image for a given icon name. - * <p/> - * Callers should not dispose it. - * - * @param osName The leaf name, without the extension, of an existing icon in the - * editor's "icons" directory. If it doesn't exists, a default icon will be - * generated automatically based on the name. - * @param color The color of the text in the automatically generated icons, - * one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED. - * @param shape The shape of the icon in the automatically generated icons, - * one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT. - */ - public Image getIcon(String osName, int color, int shape) { - String key = Character.toString((char) shape) + Integer.toString(color) + osName; - Image icon = mIconMap.get(key); - if (icon == null && !mIconMap.containsKey(key)) { - ImageDescriptor id = getImageDescriptor(osName, color, shape); - if (id != null) { - icon = id.createImage(); - } - // Note that we store null references in the icon map, to avoid looking them - // up every time. If it didn't exist once, it will not exist later. - mIconMap.put(key, icon); - } - return icon; - } - - /** - * Returns an ImageDescriptor for a given icon name. - * <p/> - * Callers should not dispose it. - * - * @param osName The leaf name, without the extension, of an existing icon in the - * editor's "icons" directory. If it doesn't exists, a default icon will be - * generated automatically based on the name. - */ - public ImageDescriptor getImageDescriptor(String osName) { - return getImageDescriptor(osName, COLOR_DEFAULT, SHAPE_DEFAULT); - } - - /** - * Returns an ImageDescriptor for a given icon name. - * <p/> - * Callers should not dispose it. - * - * @param osName The leaf name, without the extension, of an existing icon in the - * editor's "icons" directory. If it doesn't exists, a default icon will be - * generated automatically based on the name. - * @param color The color of the text in the automatically generated icons. - * one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED. - * @param shape The shape of the icon in the automatically generated icons, - * one of SHAPE_DEFAULT, SHAPE_CIRCLE or SHAPE_RECT. - */ - public ImageDescriptor getImageDescriptor(String osName, int color, int shape) { - String key = Character.toString((char) shape) + Integer.toString(color) + osName; - ImageDescriptor id = mImageDescMap.get(key); - if (id == null && !mImageDescMap.containsKey(key)) { - id = AdtPlugin.imageDescriptorFromPlugin( - AdtPlugin.PLUGIN_ID, - String.format("/icons/%1$s.png", osName)); //$NON-NLS-1$ - - if (id == null) { - id = new LetterImageDescriptor(osName.charAt(0), color, shape); - } - - // Note that we store null references in the icon map, to avoid looking them - // up every time. If it didn't exist once, it will not exist later. - mImageDescMap.put(key, id); - } - return id; - } - - /** - * A simple image description that generates a 16x16 image which consists - * of a colored letter inside a black & white circle. - */ - private static class LetterImageDescriptor extends ImageDescriptor { - - private final char mLetter; - private final int mColor; - private final int mShape; - - public LetterImageDescriptor(char letter, int color, int shape) { - mLetter = letter; - mColor = color; - mShape = shape; - } - - @Override - public ImageData getImageData() { - - final int SX = 15; - final int SY = 15; - final int RX = 4; - final int RY = 4; - - Display display = Display.getCurrent(); - if (display == null) { - return null; - } - - Image image = new Image(display, SX, SY); - - image.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); - - GC gc = new GC(image); - gc.setAdvanced(true); - gc.setAntialias(SWT.ON); - gc.setTextAntialias(SWT.ON); - - gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); - if (mShape == SHAPE_CIRCLE) { - gc.fillOval(0, 0, SX - 1, SY - 1); - } else if (mShape == SHAPE_RECT) { - gc.fillRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY); - } - - gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); - gc.setLineWidth(1); - if (mShape == SHAPE_CIRCLE) { - gc.drawOval(0, 0, SX - 1, SY - 1); - } else if (mShape == SHAPE_RECT) { - gc.drawRoundRectangle(0, 0, SX - 1, SY - 1, RX, RY); - } - - // Get a bold version of the default system font, if possible. - Font font = display.getSystemFont(); - FontData[] fds = font.getFontData(); - fds[0].setStyle(SWT.BOLD); - // use 3/4th of the circle diameter for the font size (in pixels) - // and convert it to "font points" (font points in SWT are hardcoded in an - // arbitrary 72 dpi and then converted in real pixels using whatever is - // indicated by getDPI -- at least that's how it works under Win32). - fds[0].setHeight((int) ((SY + 1) * 3./4. * 72./display.getDPI().y)); - // Note: win32 implementation always uses fds[0] so we change just that one. - // getFontData indicates that the array of fd is really an unusual thing for X11. - font = new Font(display, fds); - gc.setFont(font); - gc.setForeground(display.getSystemColor(mColor)); - - // Text measurement varies so slightly depending on the platform - int ofx = 0; - int ofy = 0; - if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) { - ofx = +1; - ofy = -1; - } - - String s = Character.toString(mLetter).toUpperCase(); - Point p = gc.textExtent(s); - int tx = (SX + ofx - p.x) / 2; - int ty = (SY + ofy - p.y) / 2; - gc.drawText(s, tx, ty, true /* isTransparent */); - - font.dispose(); - gc.dispose(); - - ImageData data = image.getImageData(); - image.dispose(); - return data; - } - - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java deleted file mode 100644 index e0ec86b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.swt.graphics.Image; - -/** - * {@link AttributeDescriptor} describes an XML attribute with its XML attribute name. - * <p/> - * An attribute descriptor also knows which UI node should be instantiated to represent - * this particular attribute (e.g. text field, icon chooser, class selector, etc.) - * Some attributes may be hidden and have no user interface at all. - * <p/> - * This is an abstract class. Derived classes must implement data description and return - * the correct UiAttributeNode-derived class. - */ -public abstract class AttributeDescriptor { - private String mXmlLocalName; - private ElementDescriptor mParent; - private final String mNsUri; - private boolean mDeprecated; - - /** - * Creates a new {@link AttributeDescriptor} - * - * @param xmlLocalName The XML name of the attribute (case sensitive) - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - */ - public AttributeDescriptor(String xmlLocalName, String nsUri) { - mXmlLocalName = xmlLocalName; - mNsUri = nsUri; - } - - /** - * Returns the XML local name of the attribute (case sensitive) - */ - public final String getXmlLocalName() { - return mXmlLocalName; - } - - public final String getNamespaceUri() { - return mNsUri; - } - - final void setParent(ElementDescriptor parent) { - mParent = parent; - } - - public final ElementDescriptor getParent() { - return mParent; - } - - public void setDeprecated(boolean isDeprecated) { - mDeprecated = isDeprecated; - } - - public boolean isDeprecated() { - return mDeprecated; - } - - /** - * Returns an optional icon for the attribute. - * <p/> - * By default this tries to return an icon based on the XML name of the attribute. - * If this fails, it tries to return the default Android logo as defined in the - * plugin. If all fails, it returns null. - * - * @return An icon for this element or null. - */ - public Image getIcon() { - IconFactory factory = IconFactory.getInstance(); - Image icon; - icon = factory.getIcon(getXmlLocalName(), IconFactory.COLOR_RED, IconFactory.SHAPE_CIRCLE); - return icon != null ? icon : AdtPlugin.getAndroidLogo(); - } - - /** - * @param uiParent The {@link UiElementNode} parent of this UI attribute. - * @return A new {@link UiAttributeNode} linked to this descriptor or null if this - * attribute has no user interface. - */ - public abstract UiAttributeNode createUiNode(UiElementNode uiParent); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java deleted file mode 100644 index 2729565..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.uimodel.UiAbstractTextAttributeNode; - -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.swt.graphics.Image; - -/** - * Label provider for {@link UiAbstractTextAttributeNode}. - */ -public class AttributeDescriptorLabelProvider implements ILabelProvider { - - private final static AttributeDescriptorLabelProvider sThis = - new AttributeDescriptorLabelProvider(); - - public static ILabelProvider getProvider() { - return sThis; - } - - public Image getImage(Object element) { - if (element instanceof UiAbstractTextAttributeNode) { - UiAbstractTextAttributeNode node = (UiAbstractTextAttributeNode) element; - if (node.getDescriptor().isDeprecated()) { - String v = node.getCurrentValue(); - if (v != null && v.length() > 0) { - IconFactory factory = IconFactory.getInstance(); - return factory.getIcon("warning"); //$NON-NLS-1$ - } - } - } - - return null; - } - - public String getText(Object element) { - if (element instanceof UiAbstractTextAttributeNode) { - return ((UiAbstractTextAttributeNode)element).getCurrentValue(); - } - - return null; - } - - public void addListener(ILabelProviderListener listener) { - // TODO Auto-generated method stub - - } - - public void dispose() { - // TODO Auto-generated method stub - - } - - public boolean isLabelProperty(Object element, String property) { - // TODO Auto-generated method stub - return false; - } - - public void removeListener(ILabelProviderListener listener) { - // TODO Auto-generated method stub - - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/BooleanAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/BooleanAttributeDescriptor.java deleted file mode 100644 index 9ebf5f1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/BooleanAttributeDescriptor.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.editors.uimodel.UiListAttributeNode; - -/** - * Describes a text attribute that can only contain boolean values. - * It is displayed by a {@link UiListAttributeNode}. - */ -public class BooleanAttributeDescriptor extends ListAttributeDescriptor { - - public BooleanAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip, - new String[] { "true", "false" } ); - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java deleted file mode 100644 index cc923bf..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo.Format; -import com.android.ide.eclipse.editors.layout.LayoutConstants; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.swt.graphics.Image; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -/** - * Utility methods related to descriptors handling. - */ -public final class DescriptorsUtils { - - private static final String DEFAULT_WIDGET_PREFIX = "widget"; - - private static final int JAVADOC_BREAK_LENGTH = 60; - - /** - * The path in the online documentation for the manifest description. - * <p/> - * This is NOT a complete URL. To be used, it needs to be appended - * to {@link AndroidConstants#CODESITE_BASE_URL} or to the local SDK - * documentation. - */ - public static final String MANIFEST_SDK_URL = "/reference/android/R.styleable.html#"; //$NON-NLS-1$ - - public static final String IMAGE_KEY = "image"; //$NON-NLS-1$ - - private static final String CODE = "$code"; //$NON-NLS-1$ - private static final String LINK = "$link"; //$NON-NLS-1$ - private static final String ELEM = "$elem"; //$NON-NLS-1$ - private static final String BREAK = "$break"; //$NON-NLS-1$ - - /** - * The {@link ITextAttributeCreator} interface is used by the appendAttribute() method - * to provide a way for caller to override the kind of {@link TextAttributeDescriptor} - * created for a give XML attribute name. - */ - public interface ITextAttributeCreator { - /** - * Creates a new {@link TextAttributeDescriptor} instance for the given XML name, - * UI name and tooltip. - * - * @param xmlName The XML attribute name. - * @param uiName The UI attribute name. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param tooltip An optional tooltip. - * @return A new {@link TextAttributeDescriptor} (or derived) instance. - */ - public TextAttributeDescriptor create(String xmlName, String uiName, String nsUri, - String tooltip); - } - - /** - * Add all {@link AttributeInfo} to the the array of {@link AttributeDescriptor}. - * - * @param attributes The list of {@link AttributeDescriptor} to append to - * @param elementXmlName Optional XML local name of the element to which attributes are - * being added. When not null, this is used to filter overrides. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param infos The array of {@link AttributeInfo} to read and append to attributes - * @param requiredAttributes An optional set of attributes to mark as "required" (i.e. append - * a "*" to their UI name as a hint for the user.) If not null, must contains - * entries in the form "elem-name/attr-name". Elem-name can be "*". - * @param overrides A map [attribute name => TextAttributeDescriptor creator]. A creator - * can either by a Class<? extends TextAttributeDescriptor> or an instance of - * {@link ITextAttributeCreator} that instantiates the right TextAttributeDescriptor. - */ - public static void appendAttributes(ArrayList<AttributeDescriptor> attributes, - String elementXmlName, - String nsUri, AttributeInfo[] infos, - Set<String> requiredAttributes, - Map<String, Object> overrides) { - for (AttributeInfo info : infos) { - boolean required = false; - if (requiredAttributes != null) { - String attr_name = info.getName(); - if (requiredAttributes.contains("*/" + attr_name) || - requiredAttributes.contains(elementXmlName + "/" + attr_name)) { - required = true; - } - } - appendAttribute(attributes, elementXmlName, nsUri, info, required, overrides); - } - } - - /** - * Add an {@link AttributeInfo} to the the array of {@link AttributeDescriptor}. - * - * @param attributes The list of {@link AttributeDescriptor} to append to - * @param elementXmlName Optional XML local name of the element to which attributes are - * being added. When not null, this is used to filter overrides. - * @param info The {@link AttributeInfo} to append to attributes - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param required True if the attribute is to be marked as "required" (i.e. append - * a "*" to its UI name as a hint for the user.) - * @param overrides A map [attribute name => TextAttributeDescriptor creator]. A creator - * can either by a Class<? extends TextAttributeDescriptor> or an instance of - * {@link ITextAttributeCreator} that instantiates the right TextAttributeDescriptor. - */ - public static void appendAttribute(ArrayList<AttributeDescriptor> attributes, - String elementXmlName, - String nsUri, - AttributeInfo info, boolean required, - Map<String, Object> overrides) { - AttributeDescriptor attr = null; - - String xmlLocalName = info.getName(); - String uiName = prettyAttributeUiName(info.getName()); // ui_name - if (required) { - uiName += "*"; //$NON-NLS-1$ - } - - String tooltip = null; - String rawTooltip = info.getJavaDoc(); - if (rawTooltip == null) { - rawTooltip = ""; - } - - String deprecated = info.getDeprecatedDoc(); - if (deprecated != null) { - if (rawTooltip.length() > 0) { - rawTooltip += "@@"; //$NON-NLS-1$ insert a break - } - rawTooltip += "* Deprecated"; - if (deprecated.length() != 0) { - rawTooltip += ": " + deprecated; //$NON-NLS-1$ - } - if (deprecated.length() == 0 || !deprecated.endsWith(".")) { //$NON-NLS-1$ - rawTooltip += "."; //$NON-NLS-1$ - } - } - - // Add the known types to the tooltip - Format[] formats_list = info.getFormats(); - int flen = formats_list.length; - if (flen > 0) { - // Fill the formats in a set for faster access - HashSet<Format> formats_set = new HashSet<Format>(); - - StringBuilder sb = new StringBuilder(); - if (rawTooltip != null && rawTooltip.length() > 0) { - sb.append(rawTooltip); - sb.append(" "); //$NON-NLS-1$ - } - if (sb.length() > 0) { - sb.append("@@"); //$NON-NLS-1$ @@ inserts a break before the types - } - sb.append("["); //$NON-NLS-1$ - for (int i = 0; i < flen; i++) { - Format f = formats_list[i]; - formats_set.add(f); - - sb.append(f.toString().toLowerCase()); - if (i < flen - 1) { - sb.append(", "); //$NON-NLS-1$ - } - } - // The extra space at the end makes the tooltip more readable on Windows. - sb.append("]"); //$NON-NLS-1$ - - if (required) { - sb.append(".@@* "); //$NON-NLS-1$ @@ inserts a break. - sb.append("Required."); - } - - // The extra space at the end makes the tooltip more readable on Windows. - sb.append(" "); //$NON-NLS-1$ - - rawTooltip = sb.toString(); - tooltip = formatTooltip(rawTooltip); - - // Create a specialized attribute if we can - if (overrides != null) { - for (Entry<String, Object> entry: overrides.entrySet()) { - String key = entry.getKey(); - String elements[] = key.split("/"); //$NON-NLS-1$ - String overrideAttrLocalName = null; - if (elements.length < 1) { - continue; - } else if (elements.length == 1) { - overrideAttrLocalName = elements[0]; - elements = null; - } else { - overrideAttrLocalName = elements[elements.length - 1]; - elements = elements[0].split(","); //$NON-NLS-1$ - } - - if (overrideAttrLocalName == null || - !overrideAttrLocalName.equals(xmlLocalName)) { - continue; - } - - boolean ok_element = elements.length < 1; - if (!ok_element) { - for (String element : elements) { - if (element.equals("*") //$NON-NLS-1$ - || element.equals(elementXmlName)) { - ok_element = true; - break; - } - } - } - - if (!ok_element) { - continue; - } - - Object override = entry.getValue(); - if (override instanceof Class) { - try { - // The override is instance of the class to create, which must - // have a constructor compatible with TextAttributeDescriptor. - @SuppressWarnings("unchecked") //$NON-NLS-1$ - Class<? extends TextAttributeDescriptor> clazz = - (Class<? extends TextAttributeDescriptor>) override; - Constructor<? extends TextAttributeDescriptor> cons; - cons = clazz.getConstructor(new Class<?>[] { - String.class, String.class, String.class, String.class } ); - attr = cons.newInstance( - new Object[] { xmlLocalName, uiName, nsUri, tooltip }); - } catch (SecurityException e) { - // ignore - } catch (NoSuchMethodException e) { - // ignore - } catch (IllegalArgumentException e) { - // ignore - } catch (InstantiationException e) { - // ignore - } catch (IllegalAccessException e) { - // ignore - } catch (InvocationTargetException e) { - // ignore - } - } else if (override instanceof ITextAttributeCreator) { - attr = ((ITextAttributeCreator) override).create( - xmlLocalName, uiName, nsUri, tooltip); - } - } - } // if overrides - - // Create a specialized descriptor if we can, based on type - if (attr == null) { - if (formats_set.contains(Format.REFERENCE)) { - // This is either a multi-type reference or a generic reference. - attr = new ReferenceAttributeDescriptor(xmlLocalName, uiName, nsUri, tooltip); - } else if (formats_set.contains(Format.ENUM)) { - attr = new ListAttributeDescriptor(xmlLocalName, uiName, nsUri, tooltip, - info.getEnumValues()); - } else if (formats_set.contains(Format.FLAG)) { - attr = new FlagAttributeDescriptor(xmlLocalName, uiName, nsUri, tooltip, - info.getFlagValues()); - } else if (formats_set.contains(Format.BOOLEAN)) { - attr = new BooleanAttributeDescriptor(xmlLocalName, uiName, nsUri, tooltip); - } else if (formats_set.contains(Format.STRING)) { - attr = new ReferenceAttributeDescriptor(ResourceType.STRING, - xmlLocalName, uiName, nsUri, - tooltip); - } - } - } - - // By default a simple text field is used - if (attr == null) { - if (tooltip == null) { - tooltip = formatTooltip(rawTooltip); - } - attr = new TextAttributeDescriptor(xmlLocalName, uiName, nsUri, tooltip); - } - attr.setDeprecated(info.getDeprecatedDoc() != null); - attributes.add(attr); - } - - /** - * Indicates the the given {@link AttributeInfo} already exists in the ArrayList of - * {@link AttributeDescriptor}. This test for the presence of a descriptor with the same - * XML name. - * - * @param attributes The list of {@link AttributeDescriptor} to compare to. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link AndroidConstants#NS_RESOURCES} for a common value. - * @param info The {@link AttributeInfo} to know whether it is included in the above list. - * @return True if this {@link AttributeInfo} is already present in - * the {@link AttributeDescriptor} list. - */ - public static boolean containsAttribute(ArrayList<AttributeDescriptor> attributes, - String nsUri, - AttributeInfo info) { - String xmlLocalName = info.getName(); - for (AttributeDescriptor desc : attributes) { - if (desc.getXmlLocalName().equals(xmlLocalName)) { - if (nsUri == desc.getNamespaceUri() || - (nsUri != null && nsUri.equals(desc.getNamespaceUri()))) { - return true; - } - } - } - return false; - } - - /** - * Create a pretty attribute UI name from an XML name. - * <p/> - * The original xml name starts with a lower case and is camel-case, - * e.g. "maxWidthForView". The pretty name starts with an upper case - * and has space separators, e.g. "Max width for view". - */ - public static String prettyAttributeUiName(String name) { - if (name.length() < 1) { - return name; - } - StringBuffer buf = new StringBuffer(); - - char c = name.charAt(0); - // Use upper case initial letter - buf.append((char)(c >= 'a' && c <= 'z' ? c + 'A' - 'a' : c)); - int len = name.length(); - for (int i = 1; i < len; i++) { - c = name.charAt(i); - if (c >= 'A' && c <= 'Z') { - // Break camel case into separate words - buf.append(' '); - // Use a lower case initial letter for the next word, except if the - // word is solely X, Y or Z. - if (c >= 'X' && c <= 'Z' && - (i == len-1 || - (i < len-1 && name.charAt(i+1) >= 'A' && name.charAt(i+1) <= 'Z'))) { - buf.append(c); - } else { - buf.append((char)(c - 'A' + 'a')); - } - } else if (c == '_') { - buf.append(' '); - } else { - buf.append(c); - } - } - - name = buf.toString(); - - // Replace these acronyms by upper-case versions - // - (?<=^| ) means "if preceded by a space or beginning of string" - // - (?=$| ) means "if followed by a space or end of string" - name = name.replaceAll("(?<=^| )sdk(?=$| )", "SDK"); - name = name.replaceAll("(?<=^| )uri(?=$| )", "URI"); - - return name; - } - - /** - * 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 || str.charAt(0) < 'a' || str.charAt(0) > 'z') { - return str; - } - - StringBuilder sb = new StringBuilder(); - sb.append((char)(str.charAt(0) + 'A' - 'a')); - sb.append(str.substring(1)); - return sb.toString(); - } - - /** - * Formats the javadoc tooltip to be usable in a tooltip. - */ - public static String formatTooltip(String javadoc) { - ArrayList<String> spans = scanJavadoc(javadoc); - - StringBuilder sb = new StringBuilder(); - boolean needBreak = false; - - for (int n = spans.size(), i = 0; i < n; ++i) { - String s = spans.get(i); - if (CODE.equals(s)) { - s = spans.get(++i); - if (s != null) { - sb.append('"').append(s).append('"'); - } - } else if (LINK.equals(s)) { - String base = spans.get(++i); - String anchor = spans.get(++i); - String text = spans.get(++i); - - if (base != null) { - base = base.trim(); - } - if (anchor != null) { - anchor = anchor.trim(); - } - if (text != null) { - text = text.trim(); - } - - // If there's no text, use the anchor if there's one - if (text == null || text.length() == 0) { - text = anchor; - } - - if (base != null && base.length() > 0) { - if (text == null || text.length() == 0) { - // If we still have no text, use the base as text - text = base; - } - } - - if (text != null) { - sb.append(text); - } - - } else if (ELEM.equals(s)) { - s = spans.get(++i); - if (s != null) { - sb.append(s); - } - } else if (BREAK.equals(s)) { - needBreak = true; - } else if (s != null) { - if (needBreak && s.trim().length() > 0) { - sb.append('\r'); - } - sb.append(s); - needBreak = false; - } - } - - return sb.toString(); - } - - /** - * Formats the javadoc tooltip to be usable in a FormText. - * <p/> - * If the descriptor can provide an icon, the caller should provide - * elementsDescriptor.getIcon() as "image" to FormText, e.g.: - * <code>formText.setImage(IMAGE_KEY, elementsDescriptor.getIcon());</code> - * - * @param javadoc The javadoc to format. Cannot be null. - * @param elementDescriptor The element descriptor parent of the javadoc. Cannot be null. - * @param androidDocBaseUrl The base URL for the documentation. Cannot be null. Should be - * <code>FrameworkResourceManager.getInstance().getDocumentationBaseUrl()</code> - */ - public static String formatFormText(String javadoc, - ElementDescriptor elementDescriptor, - String androidDocBaseUrl) { - ArrayList<String> spans = scanJavadoc(javadoc); - - String fullSdkUrl = androidDocBaseUrl + MANIFEST_SDK_URL; - String sdkUrl = elementDescriptor.getSdkUrl(); - if (sdkUrl != null && sdkUrl.startsWith(MANIFEST_SDK_URL)) { - fullSdkUrl = androidDocBaseUrl + sdkUrl; - } - - StringBuilder sb = new StringBuilder(); - - Image icon = elementDescriptor.getIcon(); - if (icon != null) { - sb.append("<form><li style=\"image\" value=\"" + //$NON-NLS-1$ - IMAGE_KEY + "\">"); //$NON-NLS-1$ - } else { - sb.append("<form><p>"); //$NON-NLS-1$ - } - - for (int n = spans.size(), i = 0; i < n; ++i) { - String s = spans.get(i); - if (CODE.equals(s)) { - s = spans.get(++i); - if (elementDescriptor.getXmlName().equals(s) && fullSdkUrl != null) { - sb.append("<a href=\""); //$NON-NLS-1$ - sb.append(fullSdkUrl); - sb.append("\">"); //$NON-NLS-1$ - sb.append(s); - sb.append("</a>"); //$NON-NLS-1$ - } else if (s != null) { - sb.append('"').append(s).append('"'); - } - } else if (LINK.equals(s)) { - String base = spans.get(++i); - String anchor = spans.get(++i); - String text = spans.get(++i); - - if (base != null) { - base = base.trim(); - } - if (anchor != null) { - anchor = anchor.trim(); - } - if (text != null) { - text = text.trim(); - } - - // If there's no text, use the anchor if there's one - if (text == null || text.length() == 0) { - text = anchor; - } - - // TODO specialize with a base URL for views, menus & other resources - // Base is empty for a local page anchor, in which case we'll replace it - // by the element SDK URL if it exists. - if ((base == null || base.length() == 0) && fullSdkUrl != null) { - base = fullSdkUrl; - } - - String url = null; - if (base != null && base.length() > 0) { - if (base.startsWith("http")) { //$NON-NLS-1$ - // If base looks an URL, use it, with the optional anchor - url = base; - if (anchor != null && anchor.length() > 0) { - // If the base URL already has an anchor, it needs to be - // removed first. If there's no anchor, we need to add "#" - int pos = url.lastIndexOf('#'); - if (pos < 0) { - url += "#"; //$NON-NLS-1$ - } else if (pos < url.length() - 1) { - url = url.substring(0, pos + 1); - } - - url += anchor; - } - } else if (text == null || text.length() == 0) { - // If we still have no text, use the base as text - text = base; - } - } - - if (url != null && text != null) { - sb.append("<a href=\""); //$NON-NLS-1$ - sb.append(url); - sb.append("\">"); //$NON-NLS-1$ - sb.append(text); - sb.append("</a>"); //$NON-NLS-1$ - } else if (text != null) { - sb.append("<b>").append(text).append("</b>"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - } else if (ELEM.equals(s)) { - s = spans.get(++i); - if (sdkUrl != null && s != null) { - sb.append("<a href=\""); //$NON-NLS-1$ - sb.append(sdkUrl); - sb.append("\">"); //$NON-NLS-1$ - sb.append(s); - sb.append("</a>"); //$NON-NLS-1$ - } else if (s != null) { - sb.append("<b>").append(s).append("</b>"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } else if (BREAK.equals(s)) { - // ignore line breaks in pseudo-HTML rendering - } else if (s != null) { - sb.append(s); - } - } - - if (icon != null) { - sb.append("</li></form>"); //$NON-NLS-1$ - } else { - sb.append("</p></form>"); //$NON-NLS-1$ - } - return sb.toString(); - } - - private static ArrayList<String> scanJavadoc(String javadoc) { - ArrayList<String> spans = new ArrayList<String>(); - - // Standardize all whitespace in the javadoc to single spaces. - if (javadoc != null) { - javadoc = javadoc.replaceAll("[ \t\f\r\n]+", " "); //$NON-NLS-1$ //$NON-NLS-2$ - } - - // Detects {@link <base>#<name> <text>} where all 3 are optional - Pattern p_link = Pattern.compile("\\{@link\\s+([^#\\}\\s]*)(?:#([^\\s\\}]*))?(?:\\s*([^\\}]*))?\\}(.*)"); //$NON-NLS-1$ - // Detects <code>blah</code> - Pattern p_code = Pattern.compile("<code>(.+?)</code>(.*)"); //$NON-NLS-1$ - // Detects @blah@, used in hard-coded tooltip descriptors - Pattern p_elem = Pattern.compile("@([\\w -]+)@(.*)"); //$NON-NLS-1$ - // Detects a buffer that starts by @@ (request for a break) - Pattern p_break = Pattern.compile("@@(.*)"); //$NON-NLS-1$ - // Detects a buffer that starts by @ < or { (one that was not matched above) - Pattern p_open = Pattern.compile("([@<\\{])(.*)"); //$NON-NLS-1$ - // Detects everything till the next potential separator, i.e. @ < or { - Pattern p_text = Pattern.compile("([^@<\\{]+)(.*)"); //$NON-NLS-1$ - - int currentLength = 0; - String text = null; - - while(javadoc != null && javadoc.length() > 0) { - Matcher m; - String s = null; - if ((m = p_code.matcher(javadoc)).matches()) { - spans.add(CODE); - spans.add(text = cleanupJavadocHtml(m.group(1))); // <code> text - javadoc = m.group(2); - if (text != null) { - currentLength += text.length(); - } - } else if ((m = p_link.matcher(javadoc)).matches()) { - spans.add(LINK); - spans.add(m.group(1)); // @link base - spans.add(m.group(2)); // @link anchor - spans.add(text = cleanupJavadocHtml(m.group(3))); // @link text - javadoc = m.group(4); - if (text != null) { - currentLength += text.length(); - } - } else if ((m = p_elem.matcher(javadoc)).matches()) { - spans.add(ELEM); - spans.add(text = cleanupJavadocHtml(m.group(1))); // @text@ - javadoc = m.group(2); - if (text != null) { - currentLength += text.length() - 2; - } - } else if ((m = p_break.matcher(javadoc)).matches()) { - spans.add(BREAK); - currentLength = 0; - javadoc = m.group(1); - } else if ((m = p_open.matcher(javadoc)).matches()) { - s = m.group(1); - javadoc = m.group(2); - } else if ((m = p_text.matcher(javadoc)).matches()) { - s = m.group(1); - javadoc = m.group(2); - } else { - // This is not supposed to happen. In case of, just use everything. - s = javadoc; - javadoc = null; - } - if (s != null && s.length() > 0) { - s = cleanupJavadocHtml(s); - - if (currentLength >= JAVADOC_BREAK_LENGTH) { - spans.add(BREAK); - currentLength = 0; - } - while (currentLength + s.length() > JAVADOC_BREAK_LENGTH) { - int pos = s.indexOf(' ', JAVADOC_BREAK_LENGTH - currentLength); - if (pos <= 0) { - break; - } - spans.add(s.substring(0, pos + 1)); - spans.add(BREAK); - currentLength = 0; - s = s.substring(pos + 1); - } - - spans.add(s); - currentLength += s.length(); - } - } - - return spans; - } - - /** - * Remove anything that looks like HTML from a javadoc snippet, as it is supported - * neither by FormText nor a standard text tooltip. - */ - private static String cleanupJavadocHtml(String s) { - if (s != null) { - s = s.replaceAll("<", "\""); //$NON-NLS-1$ $NON-NLS-2$ - s = s.replaceAll(">", "\""); //$NON-NLS-1$ $NON-NLS-2$ - s = s.replaceAll("<[^>]+>", ""); //$NON-NLS-1$ $NON-NLS-2$ - } - return s; - } - - /** - * Sets the default layout attributes for the a new UiElementNode. - * <p/> - * Note that ideally the node should already be part of a hierarchy so that its - * parent layout and previous sibling can be determined, if any. - * <p/> - * This does not override attributes which are not empty. - */ - public static void setDefaultLayoutAttributes(UiElementNode ui_node, boolean updateLayout) { - // if this ui_node is a layout and we're adding it to a document, use fill_parent for - // both W/H. Otherwise default to wrap_layout. - boolean fill = ui_node.getDescriptor().hasChildren() && - ui_node.getUiParent() instanceof UiDocumentNode; - ui_node.setAttributeValue(LayoutConstants.ATTR_LAYOUT_WIDTH, - fill ? LayoutConstants.VALUE_FILL_PARENT : LayoutConstants.VALUE_WRAP_CONTENT, - false /* override */); - ui_node.setAttributeValue(LayoutConstants.ATTR_LAYOUT_HEIGHT, - fill ? LayoutConstants.VALUE_FILL_PARENT : LayoutConstants.VALUE_WRAP_CONTENT, - false /* override */); - - String widget_id = getFreeWidgetId(ui_node.getUiRoot(), - new Object[] { ui_node.getDescriptor().getXmlLocalName(), null, null, null }); - if (widget_id != null) { - ui_node.setAttributeValue(LayoutConstants.ATTR_ID, "@+id/" + widget_id, //$NON-NLS-1$ - false /* override */); - } - - ui_node.setAttributeValue(LayoutConstants.ATTR_TEXT, widget_id, false /*override*/); - - if (updateLayout) { - UiElementNode ui_parent = ui_node.getUiParent(); - if (ui_parent != null && - ui_parent.getDescriptor().getXmlLocalName().equals( - LayoutConstants.RELATIVE_LAYOUT)) { - UiElementNode ui_previous = ui_node.getUiPreviousSibling(); - if (ui_previous != null) { - String id = ui_previous.getAttributeValue(LayoutConstants.ATTR_ID); - if (id != null && id.length() > 0) { - id = id.replace("@+", "@"); //$NON-NLS-1$ //$NON-NLS-2$ - ui_node.setAttributeValue(LayoutConstants.ATTR_LAYOUT_BELOW, id, - false /* override */); - } - } - } - } - } - - /** - * Given a UI root node, returns the first available id that matches the - * pattern "prefix%02d". - * - * @param uiNode The UI node that gives the prefix to match. - * @return A suitable generated id - */ - public static String getFreeWidgetId(UiElementNode uiNode) { - return getFreeWidgetId(uiNode.getUiRoot(), - new Object[] { uiNode.getDescriptor().getXmlLocalName(), null, null, null }); - } - - /** - * Given a UI root node, returns the first available id that matches the - * pattern "prefix%02d". - * - * For recursion purposes, a "context" is given. Since Java doesn't have in-out parameters - * in methods and we're not going to do a dedicated type, we just use an object array which - * must contain one initial item and several are built on the fly just for internal storage: - * <ul> - * <li> prefix(String): The prefix of the generated id, i.e. "widget". Cannot be null. - * <li> index(Integer): The minimum index of the generated id. Must start with null. - * <li> generated(String): The generated widget currently being searched. Must start with null. - * <li> map(Set<String>): A set of the ids collected so far when walking through the widget - * hierarchy. Must start with null. - * </ul> - * - * @param uiRoot The Ui root node where to start searching recursively. For the initial call - * you want to pass the document root. - * @param params An in-out context of parameters used during recursion, as explained above. - * @return A suitable generated id - */ - @SuppressWarnings("unchecked") - private static String getFreeWidgetId(UiElementNode uiRoot, - Object[] params) { - - Set<String> map = (Set<String>)params[3]; - if (map == null) { - params[3] = map = new HashSet<String>(); - } - - int num = params[1] == null ? 0 : ((Integer)params[1]).intValue(); - - String generated = (String) params[2]; - String prefix = (String) params[0]; - if (generated == null) { - int pos = prefix.indexOf('.'); - if (pos >= 0) { - prefix = prefix.substring(pos + 1); - } - pos = prefix.indexOf('$'); - if (pos >= 0) { - prefix = prefix.substring(pos + 1); - } - prefix = prefix.replaceAll("[^a-zA-Z]", ""); //$NON-NLS-1$ $NON-NLS-2$ - if (prefix.length() == 0) { - prefix = DEFAULT_WIDGET_PREFIX; - } - - do { - num++; - generated = String.format("%1$s%2$02d", prefix, num); //$NON-NLS-1$ - } while (map.contains(generated)); - - params[0] = prefix; - params[1] = num; - params[2] = generated; - } - - String id = uiRoot.getAttributeValue(LayoutConstants.ATTR_ID); - if (id != null) { - id = id.replace("@+id/", ""); //$NON-NLS-1$ $NON-NLS-2$ - id = id.replace("@id/", ""); //$NON-NLS-1$ $NON-NLS-2$ - if (map.add(id) && map.contains(generated)) { - - do { - num++; - generated = String.format("%1$s%2$02d", prefix, num); //$NON-NLS-1$ - } while (map.contains(generated)); - - params[1] = num; - params[2] = generated; - } - } - - for (UiElementNode uiChild : uiRoot.getUiChildren()) { - getFreeWidgetId(uiChild, params); - } - - // Note: return params[2] (not "generated") since it could have changed during recursion. - return (String) params[2]; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DocumentDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DocumentDescriptor.java deleted file mode 100644 index 7d296f7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DocumentDescriptor.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * {@link DocumentDescriptor} describes the properties expected for an XML document node. - * - * Compared to ElementDescriptor, {@link DocumentDescriptor} does not have XML name nor UI name, - * tooltip, SDK url and attributes list. - * <p/> - * It has a children list which represent all the possible roots of the document. - * <p/> - * The document nodes are "mandatory", meaning the UI node is never deleted and it may lack - * an actual XML node attached. - */ -public class DocumentDescriptor extends ElementDescriptor { - - /** - * Constructs a new {@link DocumentDescriptor} based on its XML name and children list. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * <p/> - * The XML name is never shown in the UI directly. It is however used when an icon - * needs to be found for the node. - * - * @param xml_name The XML element node name. Case sensitive. - * @param children The list of allowed children. Can be null or empty. - */ - public DocumentDescriptor(String xml_name, ElementDescriptor[] children) { - super(xml_name, children, true /* mandatory */); - } - - /** - * @return A new {@link UiElementNode} linked to this descriptor. - */ - @Override - public UiElementNode createUiNode() { - return new UiDocumentNode(this); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java deleted file mode 100644 index 5550155..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ElementDescriptor.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.swt.graphics.Image; - -import java.util.HashSet; -import java.util.Set; - -/** - * {@link ElementDescriptor} describes the properties expected for a given XML element node. - * - * {@link ElementDescriptor} have an XML name, UI name, a tooltip, an SDK url, - * an attributes list and a children list. - * - * An UI node can be "mandatory", meaning the UI node is never deleted and it may lack - * an actual XML node attached. A non-mandatory UI node MUST have an XML node attached - * and it will cease to exist when the XML node ceases to exist. - */ -public class ElementDescriptor { - /** The XML element node name. Case sensitive. */ - private String mXmlName; - /** The XML element name for the user interface, typically capitalized. */ - private String mUiName; - /** The list of allowed attributes. */ - private AttributeDescriptor[] mAttributes; - /** The list of allowed children */ - private ElementDescriptor[] mChildren; - /* An optional tooltip. Can be empty. */ - private String mTooltip; - /** An optional SKD URL. Can be empty. */ - private String mSdkUrl; - /** Whether this UI node must always exist (even for empty models). */ - private boolean mMandatory; - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name, UI name, - * tooltip, SDK url, attributes list, children list and mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param ui_name The XML element name for the user interface, typically capitalized. - * @param tooltip An optional tooltip. Can be null or empty. - * @param sdk_url An optional SKD URL. Can be null or empty. - * @param attributes The list of allowed attributes. Can be null or empty. - * @param children The list of allowed children. Can be null or empty. - * @param mandatory Whether this node must always exist (even for empty models). A mandatory - * UI node is never deleted and it may lack an actual XML node attached. A non-mandatory - * UI node MUST have an XML node attached and it will cease to exist when the XML node - * ceases to exist. - */ - public ElementDescriptor(String xml_name, String ui_name, String tooltip, String sdk_url, - AttributeDescriptor[] attributes, - ElementDescriptor[] children, - boolean mandatory) { - mMandatory = mandatory; - mXmlName = xml_name; - mUiName = ui_name; - mTooltip = (tooltip != null && tooltip.length() > 0) ? tooltip : null; - mSdkUrl = (sdk_url != null && sdk_url.length() > 0) ? sdk_url : null; - setAttributes(attributes != null ? attributes : new AttributeDescriptor[]{}); - mChildren = children != null ? children : new ElementDescriptor[]{}; - } - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name and children list. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param children The list of allowed children. Can be null or empty. - * @param mandatory Whether this node must always exist (even for empty models). A mandatory - * UI node is never deleted and it may lack an actual XML node attached. A non-mandatory - * UI node MUST have an XML node attached and it will cease to exist when the XML node - * ceases to exist. - */ - public ElementDescriptor(String xml_name, ElementDescriptor[] children, boolean mandatory) { - this(xml_name, prettyName(xml_name), null, null, null, children, mandatory); - } - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name and children list. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param children The list of allowed children. Can be null or empty. - */ - public ElementDescriptor(String xml_name, ElementDescriptor[] children) { - this(xml_name, prettyName(xml_name), null, null, null, children, false); - } - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - */ - public ElementDescriptor(String xml_name) { - this(xml_name, prettyName(xml_name), null, null, null, null, false); - } - - /** Returns whether this node must always exist (even for empty models) */ - public boolean isMandatory() { - return mMandatory; - } - - /** - * Returns the XML element node local name (case sensitive) - */ - public final String getXmlLocalName() { - int pos = mXmlName.indexOf(':'); - if (pos != -1) { - return mXmlName.substring(pos+1); - } - return mXmlName; - } - - /** Returns the XML element node name. Case sensitive. */ - public String getXmlName() { - return mXmlName; - } - - /** - * Returns the namespace of the attribute. - */ - public final String getNamespace() { - // For now we hard-code the prefix as being "android" - if (mXmlName.startsWith("android:")) { //$NON-NLs-1$ - return SdkConstants.NS_RESOURCES; - } - - return ""; //$NON-NLs-1$ - } - - - /** Returns the XML element name for the user interface, typically capitalized. */ - public String getUiName() { - return mUiName; - } - - /** - * Returns an optional icon for the element. - * <p/> - * By default this tries to return an icon based on the XML name of the element. - * If this fails, it tries to return the default Android logo as defined in the - * plugin. If all fails, it returns null. - * - * @return An icon for this element or null. - */ - public Image getIcon() { - IconFactory factory = IconFactory.getInstance(); - int color = hasChildren() ? IconFactory.COLOR_BLUE : IconFactory.COLOR_GREEN; - int shape = hasChildren() ? IconFactory.SHAPE_RECT : IconFactory.SHAPE_CIRCLE; - Image icon = factory.getIcon(mXmlName, color, shape); - return icon != null ? icon : AdtPlugin.getAndroidLogo(); - } - - /** - * Returns an optional ImageDescriptor for the element. - * <p/> - * By default this tries to return an image based on the XML name of the element. - * If this fails, it tries to return the default Android logo as defined in the - * plugin. If all fails, it returns null. - * - * @return An ImageDescriptor for this element or null. - */ - public ImageDescriptor getImageDescriptor() { - IconFactory factory = IconFactory.getInstance(); - int color = hasChildren() ? IconFactory.COLOR_BLUE : IconFactory.COLOR_GREEN; - int shape = hasChildren() ? IconFactory.SHAPE_RECT : IconFactory.SHAPE_CIRCLE; - ImageDescriptor id = factory.getImageDescriptor(mXmlName, color, shape); - return id != null ? id : AdtPlugin.getAndroidLogoDesc(); - } - - /* Returns the list of allowed attributes. */ - public AttributeDescriptor[] getAttributes() { - return mAttributes; - } - - /* Sets the list of allowed attributes. */ - public void setAttributes(AttributeDescriptor[] attributes) { - mAttributes = attributes; - for (AttributeDescriptor attribute : attributes) { - attribute.setParent(this); - } - } - - /** Returns the list of allowed children */ - public ElementDescriptor[] getChildren() { - return mChildren; - } - - /** @return True if this descriptor has children available */ - public boolean hasChildren() { - return mChildren.length > 0; - } - - /** Sets the list of allowed children. */ - public void setChildren(ElementDescriptor[] newChildren) { - mChildren = newChildren; - } - - /** - * Returns an optional tooltip. Will be null if not present. - * <p/> - * The tooltip is based on the Javadoc of the element and already processed via - * {@link DescriptorsUtils#formatTooltip(String)} to be displayed right away as - * a UI tooltip. - */ - public String getTooltip() { - return mTooltip; - } - - /** Returns an optional SKD URL. Will be null if not present. */ - public String getSdkUrl() { - return mSdkUrl; - } - - /** Sets the optional tooltip. Can be null or empty. */ - public void setTooltip(String tooltip) { - mTooltip = tooltip; - } - - /** Sets the optional SDK URL. Can be null or empty. */ - public void setSdkUrl(String sdkUrl) { - mSdkUrl = sdkUrl; - } - - /** - * @return A new {@link UiElementNode} linked to this descriptor. - */ - public UiElementNode createUiNode() { - return new UiElementNode(this); - } - - /** - * Returns the first children of this descriptor that describes the given XML element name. - * <p/> - * In recursive mode, searches the direct children first before descending in the hierarchy. - * - * @return The ElementDescriptor matching the requested XML node element name or null. - */ - public ElementDescriptor findChildrenDescriptor(String element_name, boolean recursive) { - return findChildrenDescriptorInternal(element_name, recursive, null); - } - - private ElementDescriptor findChildrenDescriptorInternal(String element_name, - boolean recursive, - Set<ElementDescriptor> visited) { - if (recursive && visited == null) { - visited = new HashSet<ElementDescriptor>(); - } - - for (ElementDescriptor e : getChildren()) { - if (e.getXmlName().equals(element_name)) { - return e; - } - } - - if (visited != null) { - visited.add(this); - } - - if (recursive) { - for (ElementDescriptor e : getChildren()) { - if (visited != null) { - if (!visited.add(e)) { // Set.add() returns false if element is already present - continue; - } - } - ElementDescriptor f = e.findChildrenDescriptorInternal(element_name, - recursive, visited); - if (f != null) { - return f; - } - } - } - - return null; - } - - /** - * Utility helper than pretty-formats an XML Name for the UI. - * This is used by the simplified constructor that takes only an XML element name. - * - * @param xml_name The XML name to convert. - * @return The XML name with dashes replaced by spaces and capitalized. - */ - private static String prettyName(String xml_name) { - char c[] = xml_name.toCharArray(); - if (c.length > 0) { - c[0] = Character.toUpperCase(c[0]); - } - return new String(c).replace("-", " "); //$NON-NLS-1$ //$NON-NLS-2$ - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/EnumAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/EnumAttributeDescriptor.java deleted file mode 100644 index cab9883..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/EnumAttributeDescriptor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiListAttributeNode; - -/** - * Describes a text attribute that can only contains some predefined values. - * It is displayed by a {@link UiListAttributeNode}. - */ -public class EnumAttributeDescriptor extends ListAttributeDescriptor { - - public EnumAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * @return A new {@link UiListAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiListAttributeNode(this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/FlagAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/FlagAttributeDescriptor.java deleted file mode 100644 index 903417b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/FlagAttributeDescriptor.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -import com.android.ide.eclipse.editors.ui.FlagValueCellEditor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiFlagAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiListAttributeNode; - -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.swt.widgets.Composite; - -/** - * Describes a text attribute that can only contains some predefined values. - * It is displayed by a {@link UiListAttributeNode}. - * - * Note: in Android resources, a "flag" is a list of fixed values where one or - * more values can be selected using an "or", e.g. "align='left|top'". - * By contrast, an "enum" is a list of fixed values of which only one can be - * selected at a given time, e.g. "gravity='right'". - * <p/> - * This class handles the "flag" case. - * The "enum" case is done using {@link ListAttributeDescriptor}. - */ -public class FlagAttributeDescriptor extends TextAttributeDescriptor { - - private String[] mNames; - - /** - * Creates a new {@link FlagAttributeDescriptor} which automatically gets its - * values from the FrameworkResourceManager. - */ - public FlagAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * Creates a new {@link FlagAttributeDescriptor} which uses the provided values. - */ - public FlagAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip, String[] names) { - super(xmlLocalName, uiName, nsUri, tooltip); - mNames = names; - } - - /** - * @return The initial names of the flags. Can be null, in which case the Framework - * resource parser should be checked. - */ - public String[] getNames() { - return mNames; - } - - /** - * @return A new {@link UiListAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiFlagAttributeNode(this, uiParent); - } - - // ------- IPropertyDescriptor Methods - - @Override - public CellEditor createPropertyEditor(Composite parent) { - return new FlagValueCellEditor(parent); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/IDescriptorProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/IDescriptorProvider.java deleted file mode 100644 index 4c115e9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/IDescriptorProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -public interface IDescriptorProvider { - - ElementDescriptor[] getRootElementDescriptors(); - - ElementDescriptor getDescriptor(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ListAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ListAttributeDescriptor.java deleted file mode 100644 index 93969e9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ListAttributeDescriptor.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.editors.ui.ListValueCellEditor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiListAttributeNode; - -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.swt.widgets.Composite; - -/** - * Describes a text attribute that can contains some predefined values. - * It is displayed by a {@link UiListAttributeNode}. - */ -public class ListAttributeDescriptor extends TextAttributeDescriptor { - - private String[] mValues = null; - - /** - * Creates a new {@link ListAttributeDescriptor} which automatically gets its - * values from the FrameworkResourceManager. - */ - public ListAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * Creates a new {@link ListAttributeDescriptor} which uses the provided values. - */ - public ListAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip, String[] values) { - super(xmlLocalName, uiName, nsUri, tooltip); - mValues = values; - } - - public String[] getValues() { - return mValues; - } - - /** - * @return A new {@link UiListAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiListAttributeNode(this, uiParent); - } - - // ------- IPropertyDescriptor Methods - - @Override - public CellEditor createPropertyEditor(Composite parent) { - return new ListValueCellEditor(parent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java deleted file mode 100644 index 336dfe2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/ReferenceAttributeDescriptor.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.ui.ResourceValueCellEditor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiResourceAttributeNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.swt.widgets.Composite; - -/** - * Describes an XML attribute displayed containing a value or a reference to a resource. - * It is displayed by a {@link UiResourceAttributeNode}. - */ -public final class ReferenceAttributeDescriptor extends TextAttributeDescriptor { - - private ResourceType mResourceType; - - /** - * Creates a reference attributes that can contain any type of resources. - * @param xmlLocalName The XML name of the attribute (case sensitive) - * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param tooltip A non-empty tooltip string or null - */ - public ReferenceAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * Creates a reference attributes that can contain a reference to a specific - * {@link ResourceType}. - * @param resourceType The specific {@link ResourceType} that this reference attribute supports. - * It can be <code>null</code>, in which case, all resource types are supported. - * @param xmlLocalName The XML name of the attribute (case sensitive) - * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param tooltip A non-empty tooltip string or null - */ - public ReferenceAttributeDescriptor(ResourceType resourceType, - String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - mResourceType = resourceType; - } - - - /** - * @return A new {@link UiResourceAttributeNode} linked to this reference descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiResourceAttributeNode(mResourceType, this, uiParent); - } - - // ------- IPropertyDescriptor Methods - - @Override - public CellEditor createPropertyEditor(Composite parent) { - return new ResourceValueCellEditor(parent); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/SeparatorAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/SeparatorAttributeDescriptor.java deleted file mode 100644 index 8fb1c7c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/SeparatorAttributeDescriptor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.descriptors; - -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiSeparatorAttributeNode; - -/** - * {@link SeparatorAttributeDescriptor} does not represent any real attribute. - * <p/> - * It is used to separate groups of attributes visually. - */ -public class SeparatorAttributeDescriptor extends AttributeDescriptor { - - /** - * Creates a new {@link SeparatorAttributeDescriptor} - */ - public SeparatorAttributeDescriptor(String label) { - super(label /* xmlLocalName */, null /* nsUri */); - } - - /** - * @return A new {@link UiAttributeNode} linked to this descriptor or null if this - * attribute has no user interface. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiSeparatorAttributeNode(this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java deleted file mode 100644 index 77fc067..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.editors.ui.TextValueCellEditor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiTextAttributeNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.ui.views.properties.IPropertyDescriptor; - - -/** - * Describes a textual XML attribute. - * <p/> - * Such an attribute has a tooltip and would typically be displayed by - * {@link UiTextAttributeNode} using a label widget and text field. - * <p/> - * This is the "default" kind of attribute. If in doubt, use this. - */ -public class TextAttributeDescriptor extends AttributeDescriptor implements IPropertyDescriptor { - private String mUiName; - private String mTooltip; - - /** - * Creates a new {@link TextAttributeDescriptor} - * - * @param xmlLocalName The XML name of the attribute (case sensitive) - * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param tooltip A non-empty tooltip string or null - */ - public TextAttributeDescriptor(String xmlLocalName, String uiName, - String nsUri, String tooltip) { - super(xmlLocalName, nsUri); - mUiName = uiName; - mTooltip = (tooltip != null && tooltip.length() > 0) ? tooltip : null; - } - - /** - * @return The UI name of the attribute. Cannot be an empty string and cannot be null. - */ - public final String getUiName() { - return mUiName; - } - - /** - * The tooltip string is either null or a non-empty string. - * <p/> - * The tooltip is based on the Javadoc of the attribute and already processed via - * {@link DescriptorsUtils#formatTooltip(String)} to be displayed right away as - * a UI tooltip. - * <p/> - * An empty string is converted to null, to match the behavior of setToolTipText() in - * {@link Control}. - * - * @return A non-empty tooltip string or null - */ - public final String getTooltip() { - return mTooltip; - } - - /** - * @return A new {@link UiTextAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiTextAttributeNode(this, uiParent); - } - - // ------- IPropertyDescriptor Methods - - public CellEditor createPropertyEditor(Composite parent) { - return new TextValueCellEditor(parent); - } - - public String getCategory() { - if (isDeprecated()) { - return "Deprecated"; - } - - ElementDescriptor parent = getParent(); - if (parent != null) { - return parent.getUiName(); - } - - return null; - } - - public String getDescription() { - return mTooltip; - } - - public String getDisplayName() { - return mUiName; - } - - public String[] getFilterFlags() { - return null; - } - - public Object getHelpContextIds() { - return null; - } - - public Object getId() { - return this; - } - - public ILabelProvider getLabelProvider() { - return AttributeDescriptorLabelProvider.getProvider(); - } - - public boolean isCompatibleWith(IPropertyDescriptor anotherProperty) { - return anotherProperty == this; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextValueDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextValueDescriptor.java deleted file mode 100644 index 2015d71..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextValueDescriptor.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiTextValueNode; - - -/** - * Describes the value of an XML element. - * <p/> - * The value is a simple text string, displayed by an {@link UiTextValueNode}. - */ -public class TextValueDescriptor extends TextAttributeDescriptor { - - /** - * Creates a new {@link TextValueDescriptor} - * - * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. - * @param tooltip A non-empty tooltip string or null - */ - public TextValueDescriptor(String uiName, String tooltip) { - super("#text" /* xmlLocalName */, uiName, null /* nsUri */, tooltip); - } - - /** - * @return A new {@link UiTextValueNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiTextValueNode(this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/XmlnsAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/XmlnsAttributeDescriptor.java deleted file mode 100644 index ed9c897..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/XmlnsAttributeDescriptor.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.descriptors; - -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - - -/** - * Describes an XMLNS attribute that is hidden. - * <p/> - * Such an attribute has no user interface and no corresponding {@link UiAttributeNode}. - * It also has a single constant default value. - * <p/> - * When loading an XML, we'll ignore this attribute. - * However when writing a new XML, we should always write this attribute. - * <p/> - * Currently this is used for the xmlns:android attribute in the manifest element. - */ -public final class XmlnsAttributeDescriptor extends AttributeDescriptor { - - /** - * URI of the reserved "xmlns" prefix, as described in - * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#normalizeDocumentAlgo - */ - public final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; //$NON-NLS-1$ - - private String mValue; - - - public XmlnsAttributeDescriptor(String defaultPrefix, String value) { - super(defaultPrefix, XMLNS_URI); - mValue = value; - } - - /** - * Returns the value of this specialized attribute descriptor, which is the URI associated - * to the declared namespace prefix. - */ - public String getValue() { - return mValue; - } - - /** - * Returns the "xmlns" prefix that is always used by this node for its namespace URI. - * This is defined by the XML specification. - */ - public String getXmlNsPrefix() { - return "xmlns"; //$NON-NLS-1$ - } - - /** - * Returns the fully-qualified attribute name, namely "xmlns:xxx" where xxx is - * the defaultPrefix passed in the constructor. - */ - public String getXmlNsName() { - return getXmlNsPrefix() + ":" + getXmlLocalName(); //$NON-NLS-1$ - } - - /** - * @return Always returns null. {@link XmlnsAttributeDescriptor} has no user interface. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java deleted file mode 100644 index 381539b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.layoutlib.api.IXmlPullParser; - -import org.xmlpull.v1.XmlPullParserException; - -import java.io.InputStream; -import java.io.Reader; - -/** - * Base implementation of an {@link IXmlPullParser} for cases where the parser is not sitting - * on top of an actual XML file. - * <p/>It's designed to work on layout files, and will most likely not work on other resource - * files. - */ -public abstract class BasePullParser implements IXmlPullParser { - - protected int mParsingState = START_DOCUMENT; - - public BasePullParser() { - } - - // --- new methods to override --- - - public abstract void onNextFromStartDocument(); - public abstract void onNextFromStartTag(); - public abstract void onNextFromEndTag(); - - // --- basic implementation of IXmlPullParser --- - - public void setFeature(String name, boolean state) throws XmlPullParserException { - if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) { - return; - } - if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) { - return; - } - throw new XmlPullParserException("Unsupported feature: " + name); - } - - public boolean getFeature(String name) { - if (FEATURE_PROCESS_NAMESPACES.equals(name)) { - return true; - } - if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { - return true; - } - return false; - } - - public void setProperty(String name, Object value) throws XmlPullParserException { - throw new XmlPullParserException("setProperty() not supported"); - } - - public Object getProperty(String name) { - return null; - } - - public void setInput(Reader in) throws XmlPullParserException { - throw new XmlPullParserException("setInput() not supported"); - } - - public void setInput(InputStream inputStream, String inputEncoding) - throws XmlPullParserException { - throw new XmlPullParserException("setInput() not supported"); - } - - public void defineEntityReplacementText(String entityName, String replacementText) - throws XmlPullParserException { - throw new XmlPullParserException("defineEntityReplacementText() not supported"); - } - - public String getNamespacePrefix(int pos) throws XmlPullParserException { - throw new XmlPullParserException("getNamespacePrefix() not supported"); - } - - public String getInputEncoding() { - return null; - } - - public String getNamespace(String prefix) { - throw new RuntimeException("getNamespace() not supported"); - } - - public int getNamespaceCount(int depth) throws XmlPullParserException { - throw new XmlPullParserException("getNamespaceCount() not supported"); - } - - public String getNamespaceUri(int pos) throws XmlPullParserException { - throw new XmlPullParserException("getNamespaceUri() not supported"); - } - - public int getColumnNumber() { - return -1; - } - - public int getLineNumber() { - return -1; - } - - public String getAttributeType(int arg0) { - return "CDATA"; - } - - public int getEventType() { - return mParsingState; - } - - public String getText() { - return null; - } - - public char[] getTextCharacters(int[] arg0) { - return null; - } - - public boolean isAttributeDefault(int arg0) { - return false; - } - - public boolean isWhitespace() { - return false; - } - - public int next() throws XmlPullParserException { - switch (mParsingState) { - case END_DOCUMENT: - throw new XmlPullParserException("Nothing after the end"); - case START_DOCUMENT: - onNextFromStartDocument(); - break; - case START_TAG: - onNextFromStartTag(); - break; - case END_TAG: - onNextFromEndTag(); - break; - case TEXT: - // not used - break; - case CDSECT: - // not used - break; - case ENTITY_REF: - // not used - break; - case IGNORABLE_WHITESPACE: - // not used - break; - case PROCESSING_INSTRUCTION: - // not used - break; - case COMMENT: - // not used - break; - case DOCDECL: - // not used - break; - } - - return mParsingState; - } - - public int nextTag() throws XmlPullParserException { - int eventType = next(); - if (eventType != START_TAG && eventType != END_TAG) { - throw new XmlPullParserException("expected start or end tag", this, null); - } - return eventType; - } - - public String nextText() throws XmlPullParserException { - if (getEventType() != START_TAG) { - throw new XmlPullParserException("parser must be on START_TAG to read next text", this, - null); - } - int eventType = next(); - if (eventType == TEXT) { - String result = getText(); - eventType = next(); - if (eventType != END_TAG) { - throw new XmlPullParserException( - "event TEXT it must be immediately followed by END_TAG", this, null); - } - return result; - } else if (eventType == END_TAG) { - return ""; - } else { - throw new XmlPullParserException("parser must be on START_TAG or TEXT to read text", - this, null); - } - } - - public int nextToken() throws XmlPullParserException { - return next(); - } - - public void require(int type, String namespace, String name) throws XmlPullParserException { - if (type != getEventType() || (namespace != null && !namespace.equals(getNamespace())) - || (name != null && !name.equals(getName()))) - throw new XmlPullParserException("expected " + TYPES[type] + getPositionDescription()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java deleted file mode 100644 index ca7cac5..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java +++ /dev/null @@ -1,2355 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.LoadStatus; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.layout.LayoutEditor.UiEditorActions; -import com.android.ide.eclipse.editors.layout.LayoutReloadMonitor.ILayoutReloadListener; -import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; -import com.android.ide.eclipse.editors.layout.parts.ElementCreateCommand; -import com.android.ide.eclipse.editors.layout.parts.UiElementEditPart; -import com.android.ide.eclipse.editors.layout.parts.UiElementsEditPartFactory; -import com.android.ide.eclipse.editors.resources.configurations.CountryCodeQualifier; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.configurations.KeyboardStateQualifier; -import com.android.ide.eclipse.editors.resources.configurations.LanguageQualifier; -import com.android.ide.eclipse.editors.resources.configurations.NavigationMethodQualifier; -import com.android.ide.eclipse.editors.resources.configurations.NetworkCodeQualifier; -import com.android.ide.eclipse.editors.resources.configurations.PixelDensityQualifier; -import com.android.ide.eclipse.editors.resources.configurations.RegionQualifier; -import com.android.ide.eclipse.editors.resources.configurations.ScreenDimensionQualifier; -import com.android.ide.eclipse.editors.resources.configurations.ScreenOrientationQualifier; -import com.android.ide.eclipse.editors.resources.configurations.TextInputMethodQualifier; -import com.android.ide.eclipse.editors.resources.configurations.TouchScreenQualifier; -import com.android.ide.eclipse.editors.resources.configurations.KeyboardStateQualifier.KeyboardState; -import com.android.ide.eclipse.editors.resources.configurations.NavigationMethodQualifier.NavigationMethod; -import com.android.ide.eclipse.editors.resources.configurations.ScreenOrientationQualifier.ScreenOrientation; -import com.android.ide.eclipse.editors.resources.configurations.TextInputMethodQualifier.TextInputMethod; -import com.android.ide.eclipse.editors.resources.configurations.TouchScreenQualifier.TouchScreenType; -import com.android.ide.eclipse.editors.resources.manager.ProjectResources; -import com.android.ide.eclipse.editors.resources.manager.ResourceFile; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.ui.tree.CopyCutAction; -import com.android.ide.eclipse.editors.ui.tree.PasteAction; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.DensityVerifier; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.DimensionVerifier; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.LanguageRegionVerifier; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.MobileCodeVerifier; -import com.android.layoutlib.api.ILayoutLog; -import com.android.layoutlib.api.ILayoutResult; -import com.android.layoutlib.api.IResourceValue; -import com.android.layoutlib.api.IStyleResourceValue; -import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.draw2d.geometry.Rectangle; -import org.eclipse.gef.DefaultEditDomain; -import org.eclipse.gef.EditPart; -import org.eclipse.gef.EditPartViewer; -import org.eclipse.gef.GraphicalViewer; -import org.eclipse.gef.SelectionManager; -import org.eclipse.gef.dnd.TemplateTransferDragSourceListener; -import org.eclipse.gef.dnd.TemplateTransferDropTargetListener; -import org.eclipse.gef.editparts.ScalableFreeformRootEditPart; -import org.eclipse.gef.palette.PaletteRoot; -import org.eclipse.gef.requests.CreationFactory; -import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette; -import org.eclipse.gef.ui.parts.SelectionSynchronizer; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.part.FileEditorInput; - -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.awt.image.Raster; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Graphical layout editor, based on GEF. - * <p/> - * To understand GEF: http://www.ibm.com/developerworks/opensource/library/os-gef/ - * <p/> - * To understand Drag'n'drop: http://www.eclipse.org/articles/Article-Workbench-DND/drag_drop.html - */ -public class GraphicalLayoutEditor extends GraphicalEditorWithPalette - implements ILayoutReloadListener { - - private final static String THEME_SEPARATOR = "----------"; //$NON-NLS-1$ - - /** Reference to the layout editor */ - private final LayoutEditor mLayoutEditor; - - /** reference to the file being edited. */ - private IFile mEditedFile; - - private Clipboard mClipboard; - private Composite mParent; - private PaletteRoot mPaletteRoot; - - private Text mCountry; - private Text mNetwork; - private Combo mLanguage; - private Combo mRegion; - private Combo mOrientation; - private Text mDensity; - private Combo mTouch; - private Combo mKeyboard; - private Combo mTextInput; - private Combo mNavigation; - private Text mSize1; - private Text mSize2; - private Combo mThemeCombo; - private Button mCreateButton; - - private Label mCountryIcon; - private Label mNetworkIcon; - private Label mLanguageIcon; - private Label mRegionIcon; - private Label mOrientationIcon; - private Label mDensityIcon; - private Label mTouchIcon; - private Label mKeyboardIcon; - private Label mTextInputIcon; - private Label mNavigationIcon; - private Label mSizeIcon; - - private Label mCurrentLayoutLabel; - - private Image mWarningImage; - private Image mMatchImage; - private Image mErrorImage; - - /** The {@link FolderConfiguration} representing the state of the UI controls */ - private FolderConfiguration mCurrentConfig = new FolderConfiguration(); - /** The {@link FolderConfiguration} being edited. */ - private FolderConfiguration mEditedConfig; - - private Map<String, Map<String, IResourceValue>> mConfiguredFrameworkRes; - private Map<String, Map<String, IResourceValue>> mConfiguredProjectRes; - private ProjectCallback mProjectCallback; - private ILayoutLog mLogger; - - private boolean mNeedsRecompute = false; - private int mPlatformThemeCount = 0; - private boolean mDisableUpdates = false; - private boolean mActive = false; - - private Runnable mFrameworkResourceChangeListener = new Runnable() { - public void run() { - // because the SDK changed we must reset the configured framework resource. - mConfiguredFrameworkRes = null; - - updateUIFromResources(); - - mThemeCombo.getParent().layout(); - - // updateUiFromFramework will reset language/region combo, so we must call - // setConfiguration after, or the settext on language/region will be lost. - if (mEditedConfig != null) { - setConfiguration(mEditedConfig); - } - - // make sure we remove the custom view loader, since its parent class loader is the - // bridge class loader. - mProjectCallback = null; - - recomputeLayout(); - } - }; - - private final Runnable mConditionalRecomputeRunnable = new Runnable() { - public void run() { - if (mActive) { - recomputeLayout(); - } else { - mNeedsRecompute = true; - } - } - }; - - private final Runnable mUiUpdateFromResourcesRunnable = new Runnable() { - public void run() { - updateUIFromResources(); - mThemeCombo.getParent().layout(); - } - }; - - public GraphicalLayoutEditor(LayoutEditor layoutEditor) { - mLayoutEditor = layoutEditor; - setEditDomain(new DefaultEditDomain(this)); - setPartName("Layout"); - - IconFactory factory = IconFactory.getInstance(); - mWarningImage = factory.getIcon("warning"); //$NON-NLS-1$ - mMatchImage = factory.getIcon("match"); //$NON-NLS-1$ - mErrorImage = factory.getIcon("error"); //$NON-NLS-1$ - - AdtPlugin.getDefault().addResourceChangedListener(mFrameworkResourceChangeListener); - } - - // ------------------------------------ - // Methods overridden from base classes - //------------------------------------ - - @Override - public void createPartControl(Composite parent) { - mParent = parent; - GridLayout gl; - GridData gd; - - mClipboard = new Clipboard(parent.getDisplay()); - - parent.setLayout(gl = new GridLayout(1, false)); - gl.marginHeight = gl.marginWidth = 0; - - // create the top part for the configuration control - int cols = 10; - - Composite topParent = new Composite(parent, SWT.NONE); - topParent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - topParent.setLayout(gl = new GridLayout(cols, false)); - - new Label(topParent, SWT.NONE).setText("MCC"); - mCountryIcon = createControlComposite(topParent, true /* grab_horizontal */); - mCountry = new Text(mCountryIcon.getParent(), SWT.BORDER); - mCountry.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mCountry.addVerifyListener(new MobileCodeVerifier()); - mCountry.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - onCountryCodeChange(); - } - }); - mCountry.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onCountryCodeChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("MNC"); - mNetworkIcon = createControlComposite(topParent, true /* grab_horizontal */); - mNetwork = new Text(mNetworkIcon.getParent(), SWT.BORDER); - mNetwork.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mNetwork.addVerifyListener(new MobileCodeVerifier()); - mNetwork.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - onNetworkCodeChange(); - } - }); - mNetwork.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onNetworkCodeChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Lang"); - mLanguageIcon = createControlComposite(topParent, true /* grab_horizontal */); - mLanguage = new Combo(mLanguageIcon.getParent(), SWT.DROP_DOWN); - mLanguage.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mLanguage.addVerifyListener(new LanguageRegionVerifier()); - mLanguage.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onLanguageChange(); - } - public void widgetSelected(SelectionEvent e) { - onLanguageChange(); - } - }); - mLanguage.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onLanguageChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Region"); - mRegionIcon = createControlComposite(topParent, true /* grab_horizontal */); - mRegion = new Combo(mRegionIcon.getParent(), SWT.DROP_DOWN); - mRegion.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mRegion.addVerifyListener(new LanguageRegionVerifier()); - mRegion.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onRegionChange(); - } - public void widgetSelected(SelectionEvent e) { - onRegionChange(); - } - }); - mRegion.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onRegionChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Orient"); - mOrientationIcon = createControlComposite(topParent, true /* grab_horizontal */); - mOrientation = new Combo(mOrientationIcon.getParent(), SWT.DROP_DOWN | SWT.READ_ONLY); - ScreenOrientation[] soValues = ScreenOrientation.values(); - mOrientation.add("(Default)"); - for (ScreenOrientation value : soValues) { - mOrientation.add(value.getDisplayValue()); - } - mOrientation.select(0); - mOrientation.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mOrientation.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onOrientationChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Density"); - mDensityIcon = createControlComposite(topParent, true /* grab_horizontal */); - mDensity = new Text(mDensityIcon.getParent(), SWT.BORDER); - mDensity.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mDensity.addVerifyListener(new DensityVerifier()); - mDensity.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - onDensityChange(); - } - }); - mDensity.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onDensityChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Touch"); - mTouchIcon = createControlComposite(topParent, true /* grab_horizontal */); - mTouch = new Combo(mTouchIcon.getParent(), SWT.DROP_DOWN | SWT.READ_ONLY); - TouchScreenType[] tstValues = TouchScreenType.values(); - mTouch.add("(Default)"); - for (TouchScreenType value : tstValues) { - mTouch.add(value.getDisplayValue()); - } - mTouch.select(0); - mTouch.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mTouch.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onTouchChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Keybrd"); - mKeyboardIcon = createControlComposite(topParent, true /* grab_horizontal */); - mKeyboard = new Combo(mKeyboardIcon.getParent(), SWT.DROP_DOWN | SWT.READ_ONLY); - KeyboardState[] ksValues = KeyboardState.values(); - mKeyboard.add("(Default)"); - for (KeyboardState value : ksValues) { - mKeyboard.add(value.getDisplayValue()); - } - mKeyboard.select(0); - mKeyboard.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mKeyboard.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onKeyboardChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Input"); - mTextInputIcon = createControlComposite(topParent, true /* grab_horizontal */); - mTextInput = new Combo(mTextInputIcon.getParent(), SWT.DROP_DOWN | SWT.READ_ONLY); - TextInputMethod[] timValues = TextInputMethod.values(); - mTextInput.add("(Default)"); - for (TextInputMethod value : timValues) { - mTextInput.add(value.getDisplayValue()); - } - mTextInput.select(0); - mTextInput.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mTextInput.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onTextInputChange(); - } - }); - - new Label(topParent, SWT.NONE).setText("Nav"); - mNavigationIcon = createControlComposite(topParent, true /* grab_horizontal */); - mNavigation = new Combo(mNavigationIcon.getParent(), SWT.DROP_DOWN | SWT.READ_ONLY); - NavigationMethod[] nValues = NavigationMethod.values(); - mNavigation.add("(Default)"); - for (NavigationMethod value : nValues) { - mNavigation.add(value.getDisplayValue()); - } - mNavigation.select(0); - mNavigation.setLayoutData(new GridData( - GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - mNavigation.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onNavigationChange(); - } - }); - - Composite labelParent = new Composite(topParent, SWT.NONE); - labelParent.setLayout(gl = new GridLayout(8, false)); - gl.marginWidth = gl.marginHeight = 0; - labelParent.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.horizontalSpan = cols; - - new Label(labelParent, SWT.NONE).setText("Editing config:"); - mCurrentLayoutLabel = new Label(labelParent, SWT.NONE); - mCurrentLayoutLabel.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL)); - gd.widthHint = 50; - - new Label(labelParent, SWT.NONE).setText("Size"); - mSizeIcon = createControlComposite(labelParent, false); - Composite sizeParent = new Composite(mSizeIcon.getParent(), SWT.NONE); - sizeParent.setLayout(gl = new GridLayout(3, false)); - gl.marginWidth = gl.marginHeight = 0; - gl.horizontalSpacing = 0; - - mSize1 = new Text(sizeParent, SWT.BORDER); - mSize1.setLayoutData(gd = new GridData()); - gd.widthHint = 30; - new Label(sizeParent, SWT.NONE).setText("x"); - mSize2 = new Text(sizeParent, SWT.BORDER); - mSize2.setLayoutData(gd = new GridData()); - gd.widthHint = 30; - - DimensionVerifier verifier = new DimensionVerifier(); - mSize1.addVerifyListener(verifier); - mSize2.addVerifyListener(verifier); - - SelectionListener sl = new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onSizeChange(); - } - public void widgetSelected(SelectionEvent e) { - onSizeChange(); - } - }; - - mSize1.addSelectionListener(sl); - mSize2.addSelectionListener(sl); - - ModifyListener sizeModifyListener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - onSizeChange(); - } - }; - - mSize1.addModifyListener(sizeModifyListener); - mSize2.addModifyListener(sizeModifyListener); - - // first separator - Label separator = new Label(labelParent, SWT.SEPARATOR | SWT.VERTICAL); - separator.setLayoutData(gd = new GridData( - GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); - gd.heightHint = 0; - - mThemeCombo = new Combo(labelParent, SWT.READ_ONLY | SWT.DROP_DOWN); - mThemeCombo.setEnabled(false); - updateUIFromResources(); - mThemeCombo.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onThemeChange(); - } - }); - - // second separator - separator = new Label(labelParent, SWT.SEPARATOR | SWT.VERTICAL); - separator.setLayoutData(gd = new GridData( - GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL)); - gd.heightHint = 0; - - mCreateButton = new Button(labelParent, SWT.PUSH | SWT.FLAT); - mCreateButton.setText("Create..."); - mCreateButton.setEnabled(false); - mCreateButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - LayoutCreatorDialog dialog = new LayoutCreatorDialog(mCreateButton.getShell(), - mEditedFile.getName(), mCurrentConfig); - if (dialog.open() == Dialog.OK) { - final FolderConfiguration config = new FolderConfiguration(); - dialog.getConfiguration(config); - - createAlternateLayout(config); - } - } - }); - - // create a new composite that will contain the standard editor controls. - Composite editorParent = new Composite(parent, SWT.NONE); - editorParent.setLayoutData(new GridData(GridData.FILL_BOTH)); - editorParent.setLayout(new FillLayout()); - super.createPartControl(editorParent); - } - - @Override - public void dispose() { - if (mFrameworkResourceChangeListener != null) { - AdtPlugin.getDefault().removeResourceChangedListener( - mFrameworkResourceChangeListener); - mFrameworkResourceChangeListener = null; - } - - LayoutReloadMonitor.getMonitor().removeListener(mEditedFile.getProject(), this); - - if (mClipboard != null) { - mClipboard.dispose(); - mClipboard = null; - } - - super.dispose(); - } - - /* (non-Javadoc) - * Creates the palette root. - */ - @Override - protected PaletteRoot getPaletteRoot() { - mPaletteRoot = PaletteFactory.createPaletteRoot(mPaletteRoot, - mLayoutEditor.getTargetData()); - return mPaletteRoot; - } - - public Clipboard getClipboard() { - return mClipboard; - } - - /** - * Save operation in the Graphical Layout Editor. - * <p/> - * In our workflow, the model is owned by the Structured XML Editor. - * The graphical layout editor just displays it -- thus we don't really - * save anything here. - * <p/> - * This must NOT call the parent editor part. At the contrary, the parent editor - * part will call this *after* having done the actual save operation. - * <p/> - * The only action this editor must do is mark the undo command stack as - * being no longer dirty. - */ - @Override - public void doSave(IProgressMonitor monitor) { - getCommandStack().markSaveLocation(); - firePropertyChange(PROP_DIRTY); - } - - @Override - protected void configurePaletteViewer() { - super.configurePaletteViewer(); - - // Create a drag source listener on an edit part that is a viewer. - // What this does is use DND with a TemplateTransfer type which is actually - // the PaletteTemplateEntry held in the PaletteRoot. - TemplateTransferDragSourceListener dragSource = - new TemplateTransferDragSourceListener(getPaletteViewer()); - - // Create a drag source on the palette viewer. - // See the drag target associated with the GraphicalViewer in configureGraphicalViewer. - getPaletteViewer().addDragSourceListener(dragSource); - } - - /* (non-javadoc) - * Configure the graphical viewer before it receives its contents. - */ - @Override - protected void configureGraphicalViewer() { - super.configureGraphicalViewer(); - - GraphicalViewer viewer = getGraphicalViewer(); - viewer.setEditPartFactory(new UiElementsEditPartFactory(mParent.getDisplay())); - viewer.setRootEditPart(new ScalableFreeformRootEditPart()); - - // Disable the following -- we don't drag *from* the GraphicalViewer yet: - // viewer.addDragSourceListener(new TemplateTransferDragSourceListener(viewer)); - - viewer.addDropTargetListener(new DropListener(viewer)); - } - - class DropListener extends TemplateTransferDropTargetListener { - public DropListener(EditPartViewer viewer) { - super(viewer); - } - - // TODO explain - @Override - protected CreationFactory getFactory(final Object template) { - return new CreationFactory() { - public Object getNewObject() { - // We don't know the newly created EditPart since "creating" new - // elements is done by ElementCreateCommand.execute() directly by - // manipulating the XML elements.. - return null; - } - - public Object getObjectType() { - return template; - } - - }; - } - } - - /* (non-javadoc) - * Set the contents of the GraphicalViewer after it has been created. - */ - @Override - protected void initializeGraphicalViewer() { - GraphicalViewer viewer = getGraphicalViewer(); - viewer.setContents(getModel()); - - IEditorInput input = getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - mEditedFile = fileInput.getFile(); - - updateUIFromResources(); - - LayoutReloadMonitor.getMonitor().addListener(mEditedFile.getProject(), this); - } else { - // really this shouldn't happen! Log it in case it happens - mEditedFile = null; - AdtPlugin.log(IStatus.ERROR, "Input is not of type FileEditorInput: %1$s", - input.toString()); - } - } - - /* (non-javadoc) - * Sets the graphicalViewer for this EditorPart. - * @param viewer the graphical viewer - */ - @Override - protected void setGraphicalViewer(GraphicalViewer viewer) { - super.setGraphicalViewer(viewer); - - // TODO: viewer.setKeyHandler() - viewer.setContextMenu(createContextMenu(viewer)); - } - - /** - * Used by LayoutEditor.UiEditorActions.selectUiNode to select a new UI Node - * created by {@link ElementCreateCommand#execute()}. - * - * @param uiNodeModel The {@link UiElementNode} to select. - */ - public void selectModel(UiElementNode uiNodeModel) { - GraphicalViewer viewer = getGraphicalViewer(); - - // Give focus to the graphical viewer (in case the outline has it) - viewer.getControl().forceFocus(); - - Object editPart = viewer.getEditPartRegistry().get(uiNodeModel); - - if (editPart instanceof EditPart) { - viewer.select((EditPart)editPart); - } - } - - - //-------------- - // Local methods - //-------------- - - public LayoutEditor getLayoutEditor() { - return mLayoutEditor; - } - - private MenuManager createContextMenu(GraphicalViewer viewer) { - MenuManager menuManager = new MenuManager(); - menuManager.setRemoveAllWhenShown(true); - menuManager.addMenuListener(new ActionMenuListener(viewer)); - - return menuManager; - } - - private class ActionMenuListener implements IMenuListener { - private final GraphicalViewer mViewer; - - public ActionMenuListener(GraphicalViewer viewer) { - mViewer = viewer; - } - - /** - * The menu is about to be shown. The menu manager has already been - * requested to remove any existing menu item. This method gets the - * tree selection and if it is of the appropriate type it re-creates - * the necessary actions. - */ - public void menuAboutToShow(IMenuManager manager) { - ArrayList<UiElementNode> selected = new ArrayList<UiElementNode>(); - - // filter selected items and only keep those we can handle - for (Object obj : mViewer.getSelectedEditParts()) { - if (obj instanceof UiElementEditPart) { - UiElementEditPart part = (UiElementEditPart) obj; - UiElementNode uiNode = part.getUiNode(); - if (uiNode != null) { - selected.add(uiNode); - } - } - } - - if (selected.size() > 0) { - doCreateMenuAction(manager, mViewer, selected); - } - } - } - - private void doCreateMenuAction(IMenuManager manager, - final GraphicalViewer viewer, - final ArrayList<UiElementNode> selected) { - if (selected != null) { - boolean hasXml = false; - for (UiElementNode uiNode : selected) { - if (uiNode.getXmlNode() != null) { - hasXml = true; - break; - } - } - - if (hasXml) { - manager.add(new CopyCutAction(mLayoutEditor, getClipboard(), - null, selected, true /* cut */)); - manager.add(new CopyCutAction(mLayoutEditor, getClipboard(), - null, selected, false /* cut */)); - - // Can't paste with more than one element selected (the selection is the target) - if (selected.size() <= 1) { - // Paste is not valid if it would add a second element on a terminal element - // which parent is a document -- an XML document can only have one child. This - // means paste is valid if the current UI node can have children or if the - // parent is not a document. - UiElementNode ui_root = selected.get(0).getUiRoot(); - if (ui_root.getDescriptor().hasChildren() || - !(ui_root.getUiParent() instanceof UiDocumentNode)) { - manager.add(new PasteAction(mLayoutEditor, getClipboard(), - selected.get(0))); - } - } - manager.add(new Separator()); - } - } - - // Append "add" and "remove" actions. They do the same thing as the add/remove - // buttons on the side. - IconFactory factory = IconFactory.getInstance(); - - final UiEditorActions uiActions = mLayoutEditor.getUiEditorActions(); - - // "Add" makes sense only if there's 0 or 1 item selected since the - // one selected item becomes the target. - if (selected == null || selected.size() <= 1) { - manager.add(new Action("Add...", factory.getImageDescriptor("add")) { //$NON-NLS-2$ - @Override - public void run() { - UiElementNode node = selected != null && selected.size() > 0 ? selected.get(0) - : null; - uiActions.doAdd(node, viewer.getControl().getShell()); - } - }); - } - - if (selected != null) { - manager.add(new Action("Remove", factory.getImageDescriptor("delete")) { //$NON-NLS-2$ - @Override - public void run() { - uiActions.doRemove(selected, viewer.getControl().getShell()); - } - }); - - manager.add(new Separator()); - - manager.add(new Action("Up", factory.getImageDescriptor("up")) { //$NON-NLS-2$ - @Override - public void run() { - uiActions.doUp(selected); - } - }); - manager.add(new Action("Down", factory.getImageDescriptor("down")) { //$NON-NLS-2$ - @Override - public void run() { - uiActions.doDown(selected); - } - }); - } - - } - - /** - * Sets the UI for the edition of a new file. - * @param configuration the configuration of the new file. - */ - public void editNewFile(FolderConfiguration configuration) { - // update the configuration UI - setConfiguration(configuration); - - // enable the create button if the current and edited config are not equals - mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false); - } - - public Rectangle getBounds() { - ScreenOrientation orientation = null; - if (mOrientation.getSelectionIndex() == 0) { - orientation = ScreenOrientation.PORTRAIT; - } else { - orientation = ScreenOrientation.getByIndex( - mOrientation.getSelectionIndex() - 1); - } - - int s1, s2; - - // get the size from the UI controls. If it fails, revert to default values. - try { - s1 = Integer.parseInt(mSize1.getText().trim()); - } catch (NumberFormatException e) { - s1 = 480; - } - - try { - s2 = Integer.parseInt(mSize2.getText().trim()); - } catch (NumberFormatException e) { - s2 = 320; - } - - // make sure s1 is bigger than s2 - if (s1 < s2) { - int tmp = s1; - s1 = s2; - s2 = tmp; - } - - switch (orientation) { - default: - case PORTRAIT: - return new Rectangle(0, 0, s2, s1); - case LANDSCAPE: - return new Rectangle(0, 0, s1, s2); - case SQUARE: - return new Rectangle(0, 0, s1, s1); - } - } - - /** - * Renders an Android View described by a {@link ViewElementDescriptor}. - * <p/>This uses the <code>wrap_content</code> mode for both <code>layout_width</code> and - * <code>layout_height</code>, and use the class name for the <code>text</code> attribute. - * @param descriptor the descriptor for the class to render. - * @return an ImageData containing the rendering or <code>null</code> if rendering failed. - */ - public ImageData renderWidget(ViewElementDescriptor descriptor) { - if (mEditedFile == null) { - return null; - } - - IAndroidTarget target = Sdk.getCurrent().getTarget(mEditedFile.getProject()); - if (target == null) { - return null; - } - - AndroidTargetData data = Sdk.getCurrent().getTargetData(target); - if (data == null) { - return null; - } - - LayoutBridge bridge = data.getLayoutBridge(); - - if (bridge.bridge != null) { // bridge can never be null. - ResourceManager resManager = ResourceManager.getInstance(); - - ProjectCallback projectCallback = null; - Map<String, Map<String, IResourceValue>> configuredProjectResources = null; - if (mEditedFile != null) { - ProjectResources projectRes = resManager.getProjectResources( - mEditedFile.getProject()); - projectCallback = new ProjectCallback(bridge.classLoader, - projectRes, mEditedFile.getProject()); - - // get the configured resources for the project - // get the resources of the file's project. - if (mConfiguredProjectRes == null && projectRes != null) { - // make sure they are loaded - projectRes.loadAll(); - - // get the project resource values based on the current config - mConfiguredProjectRes = projectRes.getConfiguredResources(mCurrentConfig); - } - - configuredProjectResources = mConfiguredProjectRes; - } else { - // we absolutely need a Map of configured project resources. - configuredProjectResources = new HashMap<String, Map<String, IResourceValue>>(); - } - - // get the framework resources - Map<String, Map<String, IResourceValue>> frameworkResources = - getConfiguredFrameworkResources(); - - if (configuredProjectResources != null && frameworkResources != null) { - // get the selected theme - int themeIndex = mThemeCombo.getSelectionIndex(); - if (themeIndex != -1) { - String theme = mThemeCombo.getItem(themeIndex); - - // change the string if it's a custom theme to make sure we can - // differentiate them - if (themeIndex >= mPlatformThemeCount) { - theme = "*" + theme; //$NON-NLS-1$ - } - - // Render a single object as described by the ViewElementDescriptor. - WidgetPullParser parser = new WidgetPullParser(descriptor); - ILayoutResult result = bridge.bridge.computeLayout(parser, - null /* projectKey */, - 300 /* width */, 300 /* height */, theme, - configuredProjectResources, frameworkResources, projectCallback, - null /* logger */); - - // update the UiElementNode with the layout info. - if (result.getSuccess() == ILayoutResult.SUCCESS) { - BufferedImage largeImage = result.getImage(); - - // we need to resize it to the actual widget size, and convert it into - // an SWT image object. - int width = result.getRootView().getRight(); - int height = result.getRootView().getBottom(); - Raster raster = largeImage.getData(new java.awt.Rectangle(width, height)); - int[] imageDataBuffer = ((DataBufferInt)raster.getDataBuffer()).getData(); - - ImageData imageData = new ImageData(width, height, 32, - new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); - - imageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0); - - return imageData; - } - } - } - } - return null; - } - - /** - * Reloads this editor, by getting the new model from the {@link LayoutEditor}. - */ - void reloadEditor() { - GraphicalViewer viewer = getGraphicalViewer(); - viewer.setContents(getModel()); - - IEditorInput input = mLayoutEditor.getEditorInput(); - setInput(input); - - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - mEditedFile = fileInput.getFile(); - } else { - // really this shouldn't happen! Log it in case it happens - mEditedFile = null; - AdtPlugin.log(IStatus.ERROR, "Input is not of type FileEditorInput: %1$s", - input.toString()); - } - } - - /** - * Update the layout editor when the Xml model is changed. - */ - void onXmlModelChanged() { - GraphicalViewer viewer = getGraphicalViewer(); - - // try to preserve the selection before changing the content - SelectionManager selMan = viewer.getSelectionManager(); - ISelection selection = selMan.getSelection(); - - try { - viewer.setContents(getModel()); - } finally { - selMan.setSelection(selection); - } - - if (mLayoutEditor.isGraphicalEditorActive()) { - recomputeLayout(); - } else { - mNeedsRecompute = true; - } - } - - /** - * Update the UI controls state with a given {@link FolderConfiguration}. - * <p/>If a qualifier is not present in the {@link FolderConfiguration} object, the UI control - * is not modified. However if the value in the control is not the default value, a warning - * icon is showed. - */ - void setConfiguration(FolderConfiguration config) { - mDisableUpdates = true; // we do not want to trigger onXXXChange when setting new values in the widgets. - - mEditedConfig = config; - mConfiguredFrameworkRes = mConfiguredProjectRes = null; - - mCountryIcon.setImage(mMatchImage); - CountryCodeQualifier countryQualifier = config.getCountryCodeQualifier(); - if (countryQualifier != null) { - mCountry.setText(String.format("%1$d", countryQualifier.getCode())); - mCurrentConfig.setCountryCodeQualifier(countryQualifier); - } else if (mCountry.getText().length() > 0) { - mCountryIcon.setImage(mWarningImage); - } - - mNetworkIcon.setImage(mMatchImage); - NetworkCodeQualifier networkQualifier = config.getNetworkCodeQualifier(); - if (networkQualifier != null) { - mNetwork.setText(String.format("%1$d", networkQualifier.getCode())); - mCurrentConfig.setNetworkCodeQualifier(networkQualifier); - } else if (mNetwork.getText().length() > 0) { - mNetworkIcon.setImage(mWarningImage); - } - - mLanguageIcon.setImage(mMatchImage); - LanguageQualifier languageQualifier = config.getLanguageQualifier(); - if (languageQualifier != null) { - mLanguage.setText(languageQualifier.getValue()); - mCurrentConfig.setLanguageQualifier(languageQualifier); - } else if (mLanguage.getText().length() > 0) { - mLanguageIcon.setImage(mWarningImage); - } - - mRegionIcon.setImage(mMatchImage); - RegionQualifier regionQualifier = config.getRegionQualifier(); - if (regionQualifier != null) { - mRegion.setText(regionQualifier.getValue()); - mCurrentConfig.setRegionQualifier(regionQualifier); - } else if (mRegion.getText().length() > 0) { - mRegionIcon.setImage(mWarningImage); - } - - mOrientationIcon.setImage(mMatchImage); - ScreenOrientationQualifier orientationQualifier = config.getScreenOrientationQualifier(); - if (orientationQualifier != null) { - mOrientation.select( - ScreenOrientation.getIndex(orientationQualifier.getValue()) + 1); - mCurrentConfig.setScreenOrientationQualifier(orientationQualifier); - } else if (mOrientation.getSelectionIndex() != 0) { - mOrientationIcon.setImage(mWarningImage); - } - - mDensityIcon.setImage(mMatchImage); - PixelDensityQualifier densityQualifier = config.getPixelDensityQualifier(); - if (densityQualifier != null) { - mDensity.setText(String.format("%1$d", densityQualifier.getValue())); - mCurrentConfig.setPixelDensityQualifier(densityQualifier); - } else if (mDensity.getText().length() > 0) { - mDensityIcon.setImage(mWarningImage); - } - - mTouchIcon.setImage(mMatchImage); - TouchScreenQualifier touchQualifier = config.getTouchTypeQualifier(); - if (touchQualifier != null) { - mTouch.select(TouchScreenType.getIndex(touchQualifier.getValue()) + 1); - mCurrentConfig.setTouchTypeQualifier(touchQualifier); - } else if (mTouch.getSelectionIndex() != 0) { - mTouchIcon.setImage(mWarningImage); - } - - mKeyboardIcon.setImage(mMatchImage); - KeyboardStateQualifier keyboardQualifier = config.getKeyboardStateQualifier(); - if (keyboardQualifier != null) { - mKeyboard.select(KeyboardState.getIndex(keyboardQualifier.getValue()) + 1); - mCurrentConfig.setKeyboardStateQualifier(keyboardQualifier); - } else if (mKeyboard.getSelectionIndex() != 0) { - mKeyboardIcon.setImage(mWarningImage); - } - - mTextInputIcon.setImage(mMatchImage); - TextInputMethodQualifier inputQualifier = config.getTextInputMethodQualifier(); - if (inputQualifier != null) { - mTextInput.select(TextInputMethod.getIndex(inputQualifier.getValue()) + 1); - mCurrentConfig.setTextInputMethodQualifier(inputQualifier); - } else if (mTextInput.getSelectionIndex() != 0) { - mTextInputIcon.setImage(mWarningImage); - } - - mNavigationIcon.setImage(mMatchImage); - NavigationMethodQualifier navigationQualifiter = config.getNavigationMethodQualifier(); - if (navigationQualifiter != null) { - mNavigation.select( - NavigationMethod.getIndex(navigationQualifiter.getValue()) + 1); - mCurrentConfig.setNavigationMethodQualifier(navigationQualifiter); - } else if (mNavigation.getSelectionIndex() != 0) { - mNavigationIcon.setImage(mWarningImage); - } - - mSizeIcon.setImage(mMatchImage); - ScreenDimensionQualifier sizeQualifier = config.getScreenDimensionQualifier(); - if (sizeQualifier != null) { - mSize1.setText(String.format("%1$d", sizeQualifier.getValue1())); - mSize2.setText(String.format("%1$d", sizeQualifier.getValue2())); - mCurrentConfig.setScreenDimensionQualifier(sizeQualifier); - } else if (mSize1.getText().length() > 0 && mSize2.getText().length() > 0) { - mSizeIcon.setImage(mWarningImage); - } - - // update the string showing the folder name - String current = config.toDisplayString(); - mCurrentLayoutLabel.setText(current != null ? current : "(Default)"); - - mDisableUpdates = false; - } - - /** - * Displays an error icon in front of all the non-null qualifiers. - */ - void displayConfigError() { - mCountryIcon.setImage(mMatchImage); - CountryCodeQualifier countryQualifier = mCurrentConfig.getCountryCodeQualifier(); - if (countryQualifier != null) { - mCountryIcon.setImage(mErrorImage); - } - - mNetworkIcon.setImage(mMatchImage); - NetworkCodeQualifier networkQualifier = mCurrentConfig.getNetworkCodeQualifier(); - if (networkQualifier != null) { - mNetworkIcon.setImage(mErrorImage); - } - - mLanguageIcon.setImage(mMatchImage); - LanguageQualifier languageQualifier = mCurrentConfig.getLanguageQualifier(); - if (languageQualifier != null) { - mLanguageIcon.setImage(mErrorImage); - } - - mRegionIcon.setImage(mMatchImage); - RegionQualifier regionQualifier = mCurrentConfig.getRegionQualifier(); - if (regionQualifier != null) { - mRegionIcon.setImage(mErrorImage); - } - - mOrientationIcon.setImage(mMatchImage); - ScreenOrientationQualifier orientationQualifier = - mCurrentConfig.getScreenOrientationQualifier(); - if (orientationQualifier != null) { - mOrientationIcon.setImage(mErrorImage); - } - - mDensityIcon.setImage(mMatchImage); - PixelDensityQualifier densityQualifier = mCurrentConfig.getPixelDensityQualifier(); - if (densityQualifier != null) { - mDensityIcon.setImage(mErrorImage); - } - - mTouchIcon.setImage(mMatchImage); - TouchScreenQualifier touchQualifier = mCurrentConfig.getTouchTypeQualifier(); - if (touchQualifier != null) { - mTouchIcon.setImage(mErrorImage); - } - - mKeyboardIcon.setImage(mMatchImage); - KeyboardStateQualifier keyboardQualifier = mCurrentConfig.getKeyboardStateQualifier(); - if (keyboardQualifier != null) { - mKeyboardIcon.setImage(mErrorImage); - } - - mTextInputIcon.setImage(mMatchImage); - TextInputMethodQualifier inputQualifier = mCurrentConfig.getTextInputMethodQualifier(); - if (inputQualifier != null) { - mTextInputIcon.setImage(mErrorImage); - } - - mNavigationIcon.setImage(mMatchImage); - NavigationMethodQualifier navigationQualifiter = - mCurrentConfig.getNavigationMethodQualifier(); - if (navigationQualifiter != null) { - mNavigationIcon.setImage(mErrorImage); - } - - mSizeIcon.setImage(mMatchImage); - ScreenDimensionQualifier sizeQualifier = mCurrentConfig.getScreenDimensionQualifier(); - if (sizeQualifier != null) { - mSizeIcon.setImage(mErrorImage); - } - - // update the string showing the folder name - String current = mCurrentConfig.toDisplayString(); - mCurrentLayoutLabel.setText(current != null ? current : "(Default)"); - } - - UiDocumentNode getModel() { - return mLayoutEditor.getUiRootNode(); - } - - void reloadPalette() { - PaletteFactory.createPaletteRoot(mPaletteRoot, mLayoutEditor.getTargetData()); - } - - private void onCountryCodeChange() { - // because mCountry triggers onCountryCodeChange at each modification, calling setText() - // will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String value = mCountry.getText(); - - // empty string, means no qualifier. - if (value.length() == 0) { - mCurrentConfig.setCountryCodeQualifier(null); - } else { - try { - CountryCodeQualifier qualifier = CountryCodeQualifier.getQualifier( - CountryCodeQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mCurrentConfig.setCountryCodeQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - // We do nothing in this case. - mCountryIcon.setImage(mErrorImage); - return; - } - } catch (NumberFormatException e) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - mCurrentConfig.setCountryCodeQualifier(null); - mCountryIcon.setImage(mErrorImage); - } - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onNetworkCodeChange() { - // because mNetwork triggers onNetworkCodeChange at each modification, calling setText() - // will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String value = mNetwork.getText(); - - // empty string, means no qualifier. - if (value.length() == 0) { - mCurrentConfig.setNetworkCodeQualifier(null); - } else { - try { - NetworkCodeQualifier qualifier = NetworkCodeQualifier.getQualifier( - NetworkCodeQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mCurrentConfig.setNetworkCodeQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - // We do nothing in this case. - mNetworkIcon.setImage(mErrorImage); - return; - } - } catch (NumberFormatException e) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - mCurrentConfig.setNetworkCodeQualifier(null); - mNetworkIcon.setImage(mErrorImage); - } - } - - // look for a file to open/create - onConfigurationChange(); - } - - /** - * Call back for language combo selection - */ - private void onLanguageChange() { - // because mLanguage triggers onLanguageChange at each modification, the filling - // of the combo with data will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String value = mLanguage.getText(); - - updateRegionUi(null /* projectResources */, null /* frameworkResources */); - - // empty string, means no qualifier. - if (value.length() == 0) { - mCurrentConfig.setLanguageQualifier(null); - } else { - LanguageQualifier qualifier = null; - String segment = LanguageQualifier.getFolderSegment(value); - if (segment != null) { - qualifier = LanguageQualifier.getQualifier(segment); - } - - if (qualifier != null) { - mCurrentConfig.setLanguageQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - mCurrentConfig.setLanguageQualifier(null); - mLanguageIcon.setImage(mErrorImage); - } - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onRegionChange() { - // because mRegion triggers onRegionChange at each modification, the filling - // of the combo with data will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String value = mRegion.getText(); - - // empty string, means no qualifier. - if (value.length() == 0) { - mCurrentConfig.setRegionQualifier(null); - } else { - RegionQualifier qualifier = null; - String segment = RegionQualifier.getFolderSegment(value); - if (segment != null) { - qualifier = RegionQualifier.getQualifier(segment); - } - - if (qualifier != null) { - mCurrentConfig.setRegionQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - mCurrentConfig.setRegionQualifier(null); - mRegionIcon.setImage(mErrorImage); - } - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onOrientationChange() { - // update the current config - int index = mOrientation.getSelectionIndex(); - if (index != 0) { - mCurrentConfig.setScreenOrientationQualifier(new ScreenOrientationQualifier( - ScreenOrientation.getByIndex(index-1))); - } else { - mCurrentConfig.setScreenOrientationQualifier(null); - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onDensityChange() { - // because mDensity triggers onDensityChange at each modification, calling setText() - // will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String value = mDensity.getText(); - - // empty string, means no qualifier. - if (value.length() == 0) { - mCurrentConfig.setPixelDensityQualifier(null); - } else { - try { - PixelDensityQualifier qualifier = PixelDensityQualifier.getQualifier( - PixelDensityQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mCurrentConfig.setPixelDensityQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - // We do nothing in this case. - return; - } - } catch (NumberFormatException e) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - // We do nothing in this case. - mDensityIcon.setImage(mErrorImage); - return; - } - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onTouchChange() { - // update the current config - int index = mTouch.getSelectionIndex(); - if (index != 0) { - mCurrentConfig.setTouchTypeQualifier(new TouchScreenQualifier( - TouchScreenType.getByIndex(index-1))); - } else { - mCurrentConfig.setTouchTypeQualifier(null); - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onKeyboardChange() { - // update the current config - int index = mKeyboard.getSelectionIndex(); - if (index != 0) { - mCurrentConfig.setKeyboardStateQualifier(new KeyboardStateQualifier( - KeyboardState.getByIndex(index-1))); - } else { - mCurrentConfig.setKeyboardStateQualifier(null); - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onTextInputChange() { - // update the current config - int index = mTextInput.getSelectionIndex(); - if (index != 0) { - mCurrentConfig.setTextInputMethodQualifier(new TextInputMethodQualifier( - TextInputMethod.getByIndex(index-1))); - } else { - mCurrentConfig.setTextInputMethodQualifier(null); - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onNavigationChange() { - // update the current config - int index = mNavigation.getSelectionIndex(); - if (index != 0) { - mCurrentConfig.setNavigationMethodQualifier(new NavigationMethodQualifier( - NavigationMethod.getByIndex(index-1))); - } else { - mCurrentConfig.setNavigationMethodQualifier(null); - } - - // look for a file to open/create - onConfigurationChange(); - } - - private void onSizeChange() { - // because mSize1 and mSize2 trigger onSizeChange at each modification, calling setText() - // will trigger notifications, and we don't want that. - if (mDisableUpdates == true) { - return; - } - - // update the current config - String size1 = mSize1.getText(); - String size2 = mSize2.getText(); - - // if only one of the strings is empty, do nothing - if ((size1.length() == 0) ^ (size2.length() == 0)) { - mSizeIcon.setImage(mErrorImage); - return; - } else if (size1.length() == 0 && size2.length() == 0) { - // both sizes are empty: remove the qualifier. - mCurrentConfig.setScreenDimensionQualifier(null); - } else { - ScreenDimensionQualifier qualifier = ScreenDimensionQualifier.getQualifier(size1, - size2); - - if (qualifier != null) { - mCurrentConfig.setScreenDimensionQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong. - // we do nothing in this case. - return; - } - } - - // look for a file to open/create - onConfigurationChange(); - } - - - /** - * Looks for a file matching the new {@link FolderConfiguration} and attempts to open it. - * <p/>If there is no match, notify the user. - */ - private void onConfigurationChange() { - mConfiguredFrameworkRes = mConfiguredProjectRes = null; - - if (mEditedFile == null || mEditedConfig == null) { - return; - } - - // get the resources of the file's project. - ProjectResources resources = ResourceManager.getInstance().getProjectResources( - mEditedFile.getProject()); - - // from the resources, look for a matching file - ResourceFile match = null; - if (resources != null) { - match = resources.getMatchingFile(mEditedFile.getName(), - ResourceFolderType.LAYOUT, - mCurrentConfig); - } - - if (match != null) { - if (match.getFile().equals(mEditedFile) == false) { - try { - IDE.openEditor( - getSite().getWorkbenchWindow().getActivePage(), - match.getFile().getIFile()); - - // we're done! - return; - } catch (PartInitException e) { - // FIXME: do something! - } - } - - // at this point, we have not opened a new file. - - // update the configuration icons with the new edited config. - setConfiguration(mEditedConfig); - - // enable the create button if the current and edited config are not equals - mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false); - - // Even though the layout doesn't change, the config changed, and referenced - // resources need to be updated. - recomputeLayout(); - } else { - // update the configuration icons with the new edited config. - displayConfigError(); - - // enable the Create button - mCreateButton.setEnabled(true); - - // display the error. - String message = String.format( - "No resources match the configuration\n \n\t%1$s\n \nChange the configuration or create:\n \n\tres/%2$s/%3$s\n \nYou can also click the 'Create' button above.", - mCurrentConfig.toDisplayString(), - mCurrentConfig.getFolderName(ResourceFolderType.LAYOUT), - mEditedFile.getName()); - showErrorInEditor(message); - } - } - - private void onThemeChange() { - int themeIndex = mThemeCombo.getSelectionIndex(); - if (themeIndex != -1) { - String theme = mThemeCombo.getItem(themeIndex); - - if (theme.equals(THEME_SEPARATOR)) { - mThemeCombo.select(0); - } - - recomputeLayout(); - } - } - - /** - * Creates a composite with no margin/spacing, and puts a {@link Label} in it with the matching - * icon. - * @param parent the parent to receive the composite - * @return the created {@link Label} object. - */ - private Label createControlComposite(Composite parent, boolean grab) { - GridLayout gl; - - Composite composite = new Composite(parent, SWT.NONE); - composite.setLayout(gl = new GridLayout(2, false)); - gl.marginHeight = gl.marginWidth = 0; - gl.horizontalSpacing = 0; - if (grab) { - composite.setLayoutData( - new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL)); - } - - // create the label - Label icon = new Label(composite, SWT.NONE); - icon.setImage(mMatchImage); - - return icon; - } - - /** - * Recomputes the layout with the help of layoutlib. - */ - void recomputeLayout() { - try { - // check that the resource exists. If the file is opened but the project is closed - // or deleted for some reason (changed from outside of eclipse), then this will - // return false; - if (mEditedFile.exists() == false) { - String message = String.format("Resource '%1$s' does not exist.", - mEditedFile.getFullPath().toString()); - - showErrorInEditor(message); - - return; - } - - IProject iProject = mEditedFile.getProject(); - - if (mEditedFile.isSynchronized(IResource.DEPTH_ZERO) == false) { - String message = String.format("%1$s is out of sync. Please refresh.", - mEditedFile.getName()); - - showErrorInEditor(message); - - // also print it in the error console. - AdtPlugin.printErrorToConsole(iProject.getName(), message); - return; - } - - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - IAndroidTarget target = currentSdk.getTarget(mEditedFile.getProject()); - if (target == null) { - showErrorInEditor("The project target is not set."); - return; - } - - AndroidTargetData data = currentSdk.getTargetData(target); - if (data == null) { - // It can happen that the workspace refreshes while the SDK is loading its - // data, which could trigger a redraw of the opened layout if some resources - // changed while Eclipse is closed. - // In this case data could be null, but this is not an error. - // We can just silently return, as all the opened editors are automatically - // refreshed once the SDK finishes loading. - if (AdtPlugin.getDefault().getSdkLoadStatus() != LoadStatus.LOADING) { - showErrorInEditor(String.format( - "The project target (%s) was not properly loaded.", - target.getName())); - } - return; - } - - // check there is actually a model (maybe the file is empty). - UiDocumentNode model = getModel(); - - if (model.getUiChildren().size() == 0) { - showErrorInEditor("No Xml content. Go to the Outline view and add nodes."); - return; - } - - LayoutBridge bridge = data.getLayoutBridge(); - - if (bridge.bridge != null) { // bridge can never be null. - ResourceManager resManager = ResourceManager.getInstance(); - - ProjectResources projectRes = resManager.getProjectResources(iProject); - if (projectRes == null) { - return; - } - - // get the resources of the file's project. - if (mConfiguredProjectRes == null) { - // make sure they are loaded - projectRes.loadAll(); - - // get the project resource values based on the current config - mConfiguredProjectRes = projectRes.getConfiguredResources(mCurrentConfig); - } - - // get the framework resources - Map<String, Map<String, IResourceValue>> frameworkResources = - getConfiguredFrameworkResources(); - - if (mConfiguredProjectRes != null && frameworkResources != null) { - if (mProjectCallback == null) { - mProjectCallback = new ProjectCallback( - bridge.classLoader, projectRes, iProject); - } - - if (mLogger == null) { - mLogger = new ILayoutLog() { - public void error(String message) { - AdtPlugin.printErrorToConsole(mEditedFile.getName(), message); - } - - public void error(Throwable error) { - String message = error.getMessage(); - if (message == null) { - message = error.getClass().getName(); - } - - PrintStream ps = new PrintStream(AdtPlugin.getErrorStream()); - error.printStackTrace(ps); - } - - public void warning(String message) { - AdtPlugin.printToConsole(mEditedFile.getName(), message); - } - }; - } - - // get the selected theme - int themeIndex = mThemeCombo.getSelectionIndex(); - if (themeIndex != -1) { - String theme = mThemeCombo.getItem(themeIndex); - - // change the string if it's a custom theme to make sure we can - // differentiate them - if (themeIndex >= mPlatformThemeCount) { - theme = "*" + theme; //$NON-NLS-1$ - } - - // Compute the layout - UiElementPullParser parser = new UiElementPullParser(getModel()); - Rectangle rect = getBounds(); - ILayoutResult result = bridge.bridge.computeLayout(parser, - iProject /* projectKey */, - rect.width, rect.height, theme, - mConfiguredProjectRes, frameworkResources, mProjectCallback, - mLogger); - - // update the UiElementNode with the layout info. - if (result.getSuccess() == ILayoutResult.SUCCESS) { - model.setEditData(result.getImage()); - - updateNodeWithBounds(result.getRootView()); - } else { - String message = result.getErrorMessage(); - - // Reset the edit data for all the nodes. - resetNodeBounds(model); - - if (message != null) { - // set the error in the top element. - model.setEditData(message); - } - } - - model.refreshUi(); - } - } - } else { - // SDK is loaded but not the layout library! - String message = null; - // check whether the bridge managed to load, or not - if (bridge.status == LoadStatus.LOADING) { - message = String.format( - "Eclipse is loading framework information and the Layout library from the SDK folder.\n%1$s will refresh automatically once the process is finished.", - mEditedFile.getName()); - } else { - message = String.format("Eclipse failed to load the framework information and the Layout library!"); - } - showErrorInEditor(message); - } - } else { - String message = String.format( - "Eclipse is loading the SDK.\n%1$s will refresh automatically once the process is finished.", - mEditedFile.getName()); - - showErrorInEditor(message); - } - } finally { - // no matter the result, we are done doing the recompute based on the latest - // resource/code change. - mNeedsRecompute = false; - } - } - - private void showErrorInEditor(String message) { - // get the model to display the error directly in the editor - UiDocumentNode model = getModel(); - - // Reset the edit data for all the nodes. - resetNodeBounds(model); - - if (message != null) { - // set the error in the top element. - model.setEditData(message); - } - - model.refreshUi(); - } - - private void resetNodeBounds(UiElementNode node) { - node.setEditData(null); - - List<UiElementNode> children = node.getUiChildren(); - for (UiElementNode child : children) { - resetNodeBounds(child); - } - } - - private void updateNodeWithBounds(ILayoutViewInfo r) { - if (r != null) { - // update the node itself, as the viewKey is the XML node in this implementation. - Object viewKey = r.getViewKey(); - if (viewKey instanceof UiElementNode) { - Rectangle bounds = new Rectangle(r.getLeft(), r.getTop(), - r.getRight()-r.getLeft(), r.getBottom() - r.getTop()); - - ((UiElementNode)viewKey).setEditData(bounds); - } - - // and then its children. - ILayoutViewInfo[] children = r.getChildren(); - if (children != null) { - for (ILayoutViewInfo child : children) { - updateNodeWithBounds(child); - } - } - } - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.layout.LayoutReloadMonitor.ILayoutReloadListener#reloadLayout(boolean, boolean, boolean) - * - * Called when the file changes triggered a redraw of the layout - */ - public void reloadLayout(boolean codeChange, boolean rChange, boolean resChange) { - boolean recompute = rChange; - - if (resChange) { - recompute = true; - - // TODO: differentiate between single and multi resource file changed, and whether the resource change affects the cache. - - // force a reparse in case a value XML file changed. - mConfiguredProjectRes = null; - - // clear the cache in the bridge in case a bitmap/9-patch changed. - IAndroidTarget target = Sdk.getCurrent().getTarget(mEditedFile.getProject()); - if (target != null) { - - AndroidTargetData data = Sdk.getCurrent().getTargetData(target); - if (data != null) { - LayoutBridge bridge = data.getLayoutBridge(); - - if (bridge.bridge != null) { - bridge.bridge.clearCaches(mEditedFile.getProject()); - } - } - } - - mParent.getDisplay().asyncExec(mUiUpdateFromResourcesRunnable); - } - - if (codeChange) { - // only recompute if the custom view loader was used to load some code. - if (mProjectCallback != null && mProjectCallback.isUsed()) { - mProjectCallback = null; - recompute = true; - } - } - - if (recompute) { - mParent.getDisplay().asyncExec(mConditionalRecomputeRunnable); - } - } - - /** - * Responds to a page change that made the Graphical editor page the activated page. - */ - void activated() { - mActive = true; - if (mNeedsRecompute) { - recomputeLayout(); - } - } - - /** - * Responds to a page change that made the Graphical editor page the deactivated page - */ - void deactivated() { - mActive = false; - } - - /** - * Updates the UI from values in the resources, such as languages, regions, themes, etc... - * This must be called from the UI thread. - */ - private void updateUIFromResources() { - - ResourceManager manager = ResourceManager.getInstance(); - - ProjectResources frameworkProject = getFrameworkResources(); - - mDisableUpdates = true; - - // Reset stuff - int selection = mThemeCombo.getSelectionIndex(); - mThemeCombo.removeAll(); - mPlatformThemeCount = 0; - mLanguage.removeAll(); - - Set<String> languages = new HashSet<String>(); - ArrayList<String> themes = new ArrayList<String>(); - - // get the themes, and languages from the Framework. - if (frameworkProject != null) { - // get the configured resources for the framework - Map<String, Map<String, IResourceValue>> frameworResources = - getConfiguredFrameworkResources(); - - if (frameworResources != null) { - // get the styles. - Map<String, IResourceValue> styles = frameworResources.get( - ResourceType.STYLE.getName()); - - - // collect the themes out of all the styles. - for (IResourceValue value : styles.values()) { - String name = value.getName(); - if (name.startsWith("Theme.") || name.equals("Theme")) { - themes.add(value.getName()); - mPlatformThemeCount++; - } - } - - // sort them and add them to the combo - Collections.sort(themes); - - for (String theme : themes) { - mThemeCombo.add(theme); - } - - mPlatformThemeCount = themes.size(); - themes.clear(); - } - // now get the languages from the framework. - Set<String> frameworkLanguages = frameworkProject.getLanguages(); - if (frameworkLanguages != null) { - languages.addAll(frameworkLanguages); - } - } - - // now get the themes and languages from the project. - ProjectResources project = null; - if (mEditedFile != null) { - project = manager.getProjectResources(mEditedFile.getProject()); - - // in cases where the opened file is not linked to a project, this could be null. - if (project != null) { - // get the configured resources for the project - if (mConfiguredProjectRes == null) { - // make sure they are loaded - project.loadAll(); - - // get the project resource values based on the current config - mConfiguredProjectRes = project.getConfiguredResources(mCurrentConfig); - } - - if (mConfiguredProjectRes != null) { - // get the styles. - Map<String, IResourceValue> styleMap = mConfiguredProjectRes.get( - ResourceType.STYLE.getName()); - - if (styleMap != null) { - // collect the themes out of all the styles, ie styles that extend, - // directly or indirectly a platform theme. - for (IResourceValue value : styleMap.values()) { - if (isTheme(value, styleMap)) { - themes.add(value.getName()); - } - } - - // sort them and add them the to the combo. - if (mPlatformThemeCount > 0 && themes.size() > 0) { - mThemeCombo.add(THEME_SEPARATOR); - } - - Collections.sort(themes); - - for (String theme : themes) { - mThemeCombo.add(theme); - } - } - } - - // now get the languages from the project. - Set<String> projectLanguages = project.getLanguages(); - if (projectLanguages != null) { - languages.addAll(projectLanguages); - } - } - } - - // add the languages to the Combo - for (String language : languages) { - mLanguage.add(language); - } - - mDisableUpdates = false; - - // and update the Region UI based on the current language - updateRegionUi(project, frameworkProject); - - // handle default selection of themes - if (mThemeCombo.getItemCount() > 0) { - mThemeCombo.setEnabled(true); - if (selection == -1) { - selection = 0; - } - - if (mThemeCombo.getItemCount() <= selection) { - mThemeCombo.select(0); - } else { - mThemeCombo.select(selection); - } - } else { - mThemeCombo.setEnabled(false); - } - } - - /** - * Returns whether the given <var>style</var> is a theme. - * This is done by making sure the parent is a theme. - * @param value the style to check - * @param styleMap the map of styles for the current project. Key is the style name. - * @return True if the given <var>style</var> is a theme. - */ - private boolean isTheme(IResourceValue value, Map<String, IResourceValue> styleMap) { - if (value instanceof IStyleResourceValue) { - IStyleResourceValue style = (IStyleResourceValue)value; - - boolean frameworkStyle = false; - String parentStyle = style.getParentStyle(); - if (parentStyle == null) { - // if there is no specified parent style we look an implied one. - // For instance 'Theme.light' is implied child style of 'Theme', - // and 'Theme.light.fullscreen' is implied child style of 'Theme.light' - String name = style.getName(); - int index = name.lastIndexOf('.'); - if (index != -1) { - parentStyle = name.substring(0, index); - } - } else { - // remove the useless @ if it's there - if (parentStyle.startsWith("@")) { - parentStyle = parentStyle.substring(1); - } - - // check for framework identifier. - if (parentStyle.startsWith("android:")) { - frameworkStyle = true; - parentStyle = parentStyle.substring("android:".length()); - } - - // at this point we could have the format style/<name>. we want only the name - if (parentStyle.startsWith("style/")) { - parentStyle = parentStyle.substring("style/".length()); - } - } - - if (frameworkStyle) { - // if the parent is a framework style, it has to be 'Theme' or 'Theme.*' - return parentStyle.equals("Theme") || parentStyle.startsWith("Theme."); - } else { - // if it's a project style, we check this is a theme. - value = styleMap.get(parentStyle); - if (value != null) { - return isTheme(value, styleMap); - } - } - } - - return false; - } - - /** - * Update the Region UI widget based on the current language selection - * @param projectResources the project resources or {@code null}. - * @param frameworkResources the framework resource or {@code null} - */ - private void updateRegionUi(ProjectResources projectResources, - ProjectResources frameworkResources) { - if (projectResources == null && mEditedFile != null) { - projectResources = ResourceManager.getInstance().getProjectResources( - mEditedFile.getProject()); - } - - if (frameworkResources == null) { - frameworkResources = getFrameworkResources(); - } - - String currentLanguage = mLanguage.getText(); - - Set<String> set = null; - - if (projectResources != null) { - set = projectResources.getRegions(currentLanguage); - } - - if (frameworkResources != null) { - if (set != null) { - Set<String> set2 = frameworkResources.getRegions(currentLanguage); - set.addAll(set2); - } else { - set = frameworkResources.getRegions(currentLanguage); - } - } - - if (set != null) { - mDisableUpdates = true; - - mRegion.removeAll(); - for (String region : set) { - mRegion.add(region); - } - - mDisableUpdates = false; - } - } - - private Map<String, Map<String, IResourceValue>> getConfiguredFrameworkResources() { - if (mConfiguredFrameworkRes == null) { - ProjectResources frameworkRes = getFrameworkResources(); - - if (frameworkRes == null) { - AdtPlugin.log(IStatus.ERROR, "Failed to get ProjectResource for the framework"); - } - - // get the framework resource values based on the current config - mConfiguredFrameworkRes = frameworkRes.getConfiguredResources(mCurrentConfig); - } - - return mConfiguredFrameworkRes; - } - - /** - * Returns the selection synchronizer object. - * The synchronizer can be used to sync the selection of 2 or more EditPartViewers. - * <p/> - * This is changed from protected to public so that the outline can use it. - * - * @return the synchronizer - */ - @Override - public SelectionSynchronizer getSelectionSynchronizer() { - return super.getSelectionSynchronizer(); - } - - /** - * Returns the edit domain. - * <p/> - * This is changed from protected to public so that the outline can use it. - * - * @return the edit domain - */ - @Override - public DefaultEditDomain getEditDomain() { - return super.getEditDomain(); - } - - /** - * Creates a new layout file from the specificed {@link FolderConfiguration}. - */ - private void createAlternateLayout(final FolderConfiguration config) { - new Job("Create Alternate Resource") { - @Override - protected IStatus run(IProgressMonitor monitor) { - // get the folder name - String folderName = config.getFolderName(ResourceFolderType.LAYOUT); - try { - - // look to see if it exists. - // get the res folder - IFolder res = (IFolder)mEditedFile.getParent().getParent(); - String path = res.getLocation().toOSString(); - - File newLayoutFolder = new File(path + File.separator + folderName); - if (newLayoutFolder.isFile()) { - // this should not happen since aapt would have complained - // before, but if one disable the automatic build, this could - // happen. - String message = String.format("File 'res/%1$s' is in the way!", - folderName); - - AdtPlugin.displayError("Layout Creation", message); - - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message); - } else if (newLayoutFolder.exists() == false) { - // create it. - newLayoutFolder.mkdir(); - } - - // now create the file - File newLayoutFile = new File(newLayoutFolder.getAbsolutePath() + - File.separator + mEditedFile.getName()); - - newLayoutFile.createNewFile(); - - InputStream input = mEditedFile.getContents(); - - FileOutputStream fos = new FileOutputStream(newLayoutFile); - - byte[] data = new byte[512]; - int count; - while ((count = input.read(data)) != -1) { - fos.write(data, 0, count); - } - - input.close(); - fos.close(); - - // refreshes the res folder to show up the new - // layout folder (if needed) and the file. - // We use a progress monitor to catch the end of the refresh - // to trigger the edit of the new file. - res.refreshLocal(IResource.DEPTH_INFINITE, new IProgressMonitor() { - public void done() { - mCurrentConfig.set(config); - mParent.getDisplay().asyncExec(new Runnable() { - public void run() { - onConfigurationChange(); - } - }); - } - - public void beginTask(String name, int totalWork) { - // pass - } - - public void internalWorked(double work) { - // pass - } - - public boolean isCanceled() { - // pass - return false; - } - - public void setCanceled(boolean value) { - // pass - } - - public void setTaskName(String name) { - // pass - } - - public void subTask(String name) { - // pass - } - - public void worked(int work) { - // pass - } - }); - } catch (IOException e2) { - String message = String.format( - "Failed to create File 'res/%1$s/%2$s' : %3$s", - folderName, mEditedFile.getName(), e2.getMessage()); - - AdtPlugin.displayError("Layout Creation", message); - - return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - message, e2); - } catch (CoreException e2) { - String message = String.format( - "Failed to create File 'res/%1$s/%2$s' : %3$s", - folderName, mEditedFile.getName(), e2.getMessage()); - - AdtPlugin.displayError("Layout Creation", message); - - return e2.getStatus(); - } - - return Status.OK_STATUS; - - } - }.schedule(); - } - - /** - * Returns a {@link ProjectResources} for the framework resources. - * @return the framework resources or null if not found. - */ - private ProjectResources getFrameworkResources() { - if (mEditedFile != null) { - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - IAndroidTarget target = currentSdk.getTarget(mEditedFile.getProject()); - - if (target != null) { - AndroidTargetData data = currentSdk.getTargetData(target); - - if (data != null) { - return data.getFrameworkResources(); - } - } - } - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutConstants.java deleted file mode 100644 index d4ec5e1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutConstants.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -/** - * A bunch of constants that map to either: - * <ul> - * <li>Android Layouts XML element names (Linear, Relative, Absolute, etc.) - * <li>Attributes for layout XML elements. - * <li>Values for attributes. - * </ul> - */ -public class LayoutConstants { - - public static final String RELATIVE_LAYOUT = "RelativeLayout"; //$NON-NLS-1$ - public static final String LINEAR_LAYOUT = "LinearLayout"; //$NON-NLS-1$ - public static final String ABSOLUTE_LAYOUT = "AbsoluteLayout"; //$NON-NLS-1$ - - public static final String ATTR_TEXT = "text"; //$NON-NLS-1$ - public static final String ATTR_ID = "id"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_HEIGHT = "layout_height"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_WIDTH = "layout_width"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_ALIGN_PARENT_TOP = "layout_alignParentTop"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_ALIGN_PARENT_BOTTOM = "layout_alignParentBottom"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_ALIGN_PARENT_LEFT = "layout_alignParentLeft";//$NON-NLS-1$ - public static final String ATTR_LAYOUT_ALIGN_PARENT_RIGHT = "layout_alignParentRight"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_ALIGN_BASELINE = "layout_alignBaseline"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_CENTER_VERTICAL = "layout_centerVertical"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_CENTER_HORIZONTAL = "layout_centerHorizontal"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_TO_RIGHT_OF = "layout_toRightOf"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_TO_LEFT_OF = "layout_toLeftOf"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_BELOW = "layout_below"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_ABOVE = "layout_above"; //$NON-NLS-1$ - - public static final String ATTR_LAYOUT_Y = "layout_y"; //$NON-NLS-1$ - public static final String ATTR_LAYOUT_X = "layout_x"; //$NON-NLS-1$ - - public static final String VALUE_WRAP_CONTENT = "wrap_content"; //$NON-NLS-1$ - public static final String VALUE_FILL_PARENT = "fill_parent"; //$NON-NLS-1$ - public static final String VALUE_TRUE = "true"; //$NON-NLS-1$ - public static final String VALUE_N_DIP = "%ddip"; //$NON-NLS-1$ - - private LayoutConstants() { - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutContentAssist.java deleted file mode 100644 index 9f39495..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutContentAssist.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.layout; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidContentAssist; - -/** - * Content Assist Processor for /res/layout XML files - */ -class LayoutContentAssist extends AndroidContentAssist { - - /** - * Constructor for LayoutContentAssist - */ - public LayoutContentAssist() { - super(AndroidTargetData.DESCRIPTOR_LAYOUT); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java deleted file mode 100644 index c4a8f5c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState; - -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.TrayDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; - -/** - * Dialog to choose a non existing {@link FolderConfiguration}. - */ -class LayoutCreatorDialog extends TrayDialog { - - private ConfigurationSelector mSelector; - private Composite mStatusComposite; - private Label mStatusLabel; - private Label mStatusImage; - - private final FolderConfiguration mConfig = new FolderConfiguration(); - private final String mFileName; - - /** - * Creates a dialog, and init the UI from a {@link FolderConfiguration}. - * @param parentShell the parent {@link Shell}. - * @param config The starting configuration. - */ - LayoutCreatorDialog(Shell parentShell, String fileName, FolderConfiguration config) { - super(parentShell); - - mFileName = fileName; - // FIXME: add some data to know what configurations already exist. - mConfig.set(config); - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite top = new Composite(parent, SWT.NONE); - top.setLayoutData(new GridData()); - top.setLayout(new GridLayout(1, false)); - - new Label(top, SWT.NONE).setText( - String.format("Configuration for the alternate version of %1$s", mFileName)); - - mSelector = new ConfigurationSelector(top); - mSelector.setConfiguration(mConfig); - - // parent's layout is a GridLayout as specified in the javadoc. - GridData gd = new GridData(); - gd.widthHint = ConfigurationSelector.WIDTH_HINT; - gd.heightHint = ConfigurationSelector.HEIGHT_HINT; - mSelector.setLayoutData(gd); - - // add a listener to check on the validity of the FolderConfiguration as - // they are built. - mSelector.setOnChangeListener(new Runnable() { - public void run() { - ConfigurationState state = mSelector.getState(); - - switch (state) { - case OK: - mSelector.getConfiguration(mConfig); - - resetStatus(); - mStatusImage.setImage(null); - getButton(IDialogConstants.OK_ID).setEnabled(true); - break; - case INVALID_CONFIG: - ResourceQualifier invalidQualifier = mSelector.getInvalidQualifier(); - mStatusLabel.setText(String.format( - "Invalid Configuration: %1$s has no filter set.", - invalidQualifier.getName())); - mStatusImage.setImage(IconFactory.getInstance().getIcon("warning")); //$NON-NLS-1$ - getButton(IDialogConstants.OK_ID).setEnabled(false); - break; - case REGION_WITHOUT_LANGUAGE: - mStatusLabel.setText( - "The Region qualifier requires the Language qualifier."); - mStatusImage.setImage(IconFactory.getInstance().getIcon("warning")); //$NON-NLS-1$ - getButton(IDialogConstants.OK_ID).setEnabled(false); - break; - } - - // need to relayout, because of the change in size in mErrorImage. - mStatusComposite.layout(); - } - }); - - mStatusComposite = new Composite(top, SWT.NONE); - mStatusComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - GridLayout gl = new GridLayout(2, false); - mStatusComposite.setLayout(gl); - gl.marginHeight = gl.marginWidth = 0; - - mStatusImage = new Label(mStatusComposite, SWT.NONE); - mStatusLabel = new Label(mStatusComposite, SWT.NONE); - mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - resetStatus(); - - return top; - } - - public void getConfiguration(FolderConfiguration config) { - config.set(mConfig); - } - - /** - * resets the status label to show the file that will be created. - */ - private void resetStatus() { - mStatusLabel.setText(String.format("New File: res/%1$s/%2$s", - mConfig.getFolderName(ResourceFolderType.LAYOUT), mFileName)); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java deleted file mode 100644 index 880ee2b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.layout; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.EclipseUiHelper; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolder; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.ui.tree.UiActions; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.gef.ui.parts.TreeViewer; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IPartListener; -import org.eclipse.ui.IShowEditorInput; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchPartSite; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.FileEditorInput; -import org.eclipse.ui.views.contentoutline.IContentOutlinePage; -import org.eclipse.ui.views.properties.IPropertySheetPage; -import org.w3c.dom.Document; - -/** - * Multi-page form editor for /res/layout XML files. - */ -public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPartListener { - - public static final String ID = AndroidConstants.EDITORS_NAMESPACE + ".layout.LayoutEditor"; //$NON-NLS-1$ - - /** Root node of the UI element hierarchy */ - private UiDocumentNode mUiRootNode; - - private GraphicalLayoutEditor mGraphicalEditor; - private int mGraphicalEditorIndex; - /** Implementation of the {@link IContentOutlinePage} for this editor */ - private UiContentOutlinePage mOutline; - /** Custom implementation of {@link IPropertySheetPage} for this editor */ - private UiPropertySheetPage mPropertyPage; - - private UiEditorActions mUiEditorActions; - - /** - * Creates the form editor for resources XML files. - */ - public LayoutEditor() { - super(); - } - - /** - * @return The root node of the UI element hierarchy - */ - @Override - public UiDocumentNode getUiRootNode() { - return mUiRootNode; - } - - // ---- Base Class Overrides ---- - - @Override - public void dispose() { - getSite().getPage().removePartListener(this); - - super.dispose(); - } - - /** - * Save the XML. - * <p/> - * The actual save operation is done in the super class by committing - * all data to the XML model and then having the Structured XML Editor - * save the XML. - * <p/> - * Here we just need to tell the graphical editor that the model has - * been saved. - */ - @Override - public void doSave(IProgressMonitor monitor) { - super.doSave(monitor); - if (mGraphicalEditor != null) { - mGraphicalEditor.doSave(monitor); - } - } - - /** - * Returns whether the "save as" operation is supported by this editor. - * <p/> - * Save-As is a valid operation for the ManifestEditor since it acts on a - * single source file. - * - * @see IEditorPart - */ - @Override - public boolean isSaveAsAllowed() { - return true; - } - - /** - * Create the various form pages. - */ - @Override - protected void createFormPages() { - try { - // The graphical layout editor is now enabled by default. - // In case there's an issue we provide a way to disable it using an - // env variable. - if (System.getenv("ANDROID_DISABLE_LAYOUT") == null) { - if (mGraphicalEditor == null) { - mGraphicalEditor = new GraphicalLayoutEditor(this); - mGraphicalEditorIndex = addPage(mGraphicalEditor, getEditorInput()); - setPageText(mGraphicalEditorIndex, mGraphicalEditor.getTitle()); - } else { - mGraphicalEditor.reloadEditor(); - } - - // update the config based on the opened file. - IEditorInput input = getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder( - fileInput.getFile()); - if (resFolder != null) { - mGraphicalEditor.editNewFile(resFolder.getConfiguration()); - } - } - - // put in place the listener to handle layout recompute only when needed. - getSite().getPage().addPartListener(this); - } - } catch (PartInitException e) { - AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$ - } - } - - /* (non-java doc) - * Change the tab/title name to include the name of the layout. - */ - @Override - protected void setInput(IEditorInput input) { - super.setInput(input); - handleNewInput(input); - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.part.EditorPart#setInputWithNotify(org.eclipse.ui.IEditorInput) - */ - @Override - protected void setInputWithNotify(IEditorInput input) { - super.setInputWithNotify(input); - handleNewInput(input); - } - - /** - * Called to replace the current {@link IEditorInput} with another one. - * <p/>This is used when {@link MatchingStrategy} returned <code>true</code> which means we're - * opening a different configuration of the same layout. - */ - public void showEditorInput(IEditorInput editorInput) { - // save the current editor input. - doSave(new NullProgressMonitor()); - - // get the current page - int currentPage = getActivePage(); - - // remove the pages, except for the graphical editor, which will be dynamically adapted - // to the new model. - // page after the graphical editor: - int count = getPageCount(); - for (int i = count - 1 ; i > mGraphicalEditorIndex ; i--) { - removePage(i); - } - // pages before the graphical editor - for (int i = mGraphicalEditorIndex - 1 ; i >= 0 ; i--) { - removePage(i); - } - - // set the current input. - setInputWithNotify(editorInput); - - // re-create or reload the pages with the default page shown as the previous active page. - createAndroidPages(); - selectDefaultPage(Integer.toString(currentPage)); - - // update the outline - if (mOutline != null && mGraphicalEditor != null) { - mOutline.reloadModel(); - } - } - - /** - * Processes the new XML Model, which XML root node is given. - * - * @param xml_doc The XML document, if available, or null if none exists. - */ - @Override - protected void xmlModelChanged(Document xml_doc) { - // init the ui root on demand - initUiRootNode(false /*force*/); - - mUiRootNode.loadFromXmlNode(xml_doc); - - // update the model first, since it is used by the viewers. - super.xmlModelChanged(xml_doc); - - if (mGraphicalEditor != null) { - mGraphicalEditor.onXmlModelChanged(); - } - - if (mOutline != null) { - mOutline.reloadModel(); - } - } - - /* (non-java doc) - * Returns the IContentOutlinePage when asked for it. - */ - @SuppressWarnings("unchecked") - @Override - public Object getAdapter(Class adapter) { - // for the outline, force it to come from the Graphical Editor. - // This fixes the case where a layout file is opened in XML view first and the outline - // gets stuck in the XML outline. - if (IContentOutlinePage.class == adapter && mGraphicalEditor != null) { - if (mOutline == null) { - mOutline = new UiContentOutlinePage(mGraphicalEditor, new TreeViewer()); - } - - return mOutline; - } - - if (IPropertySheetPage.class == adapter && mGraphicalEditor != null) { - if (mPropertyPage == null) { - mPropertyPage = new UiPropertySheetPage(); - } - - return mPropertyPage; - } - - // return default - return super.getAdapter(adapter); - } - - @Override - protected void pageChange(int newPageIndex) { - super.pageChange(newPageIndex); - - if (mGraphicalEditor != null && newPageIndex == mGraphicalEditorIndex) { - mGraphicalEditor.activated(); - } - } - - // ----- IPartListener Methods ---- - - public void partActivated(IWorkbenchPart part) { - if (part == this) { - if (mGraphicalEditor != null && getActivePage() == mGraphicalEditorIndex) { - mGraphicalEditor.activated(); - } - } - } - - public void partBroughtToTop(IWorkbenchPart part) { - partActivated(part); - } - - public void partClosed(IWorkbenchPart part) { - // pass - } - - public void partDeactivated(IWorkbenchPart part) { - if (part == this) { - if (mGraphicalEditor != null && getActivePage() == mGraphicalEditorIndex) { - mGraphicalEditor.deactivated(); - } - } - } - - public void partOpened(IWorkbenchPart part) { - EclipseUiHelper.showView(EclipseUiHelper.CONTENT_OUTLINE_VIEW_ID, false /* activate */); - EclipseUiHelper.showView(EclipseUiHelper.PROPERTY_SHEET_VIEW_ID, false /* activate */); - } - - public class UiEditorActions extends UiActions { - - @Override - protected UiDocumentNode getRootNode() { - return mUiRootNode; - } - - // Select the new item - @Override - protected void selectUiNode(UiElementNode uiNodeToSelect) { - mGraphicalEditor.selectModel(uiNodeToSelect); - } - - @Override - public void commitPendingXmlChanges() { - // Pass. There is nothing to commit before the XML is changed here. - } - } - - public UiEditorActions getUiEditorActions() { - if (mUiEditorActions == null) { - mUiEditorActions = new UiEditorActions(); - } - return mUiEditorActions; - } - - // ---- Local Methods ---- - - /** - * Returns true if the Graphics editor page is visible. - * This <b>must</b> be called from the UI thread. - */ - boolean isGraphicalEditorActive() { - IWorkbenchPartSite workbenchSite = getSite(); - IWorkbenchPage workbenchPage = workbenchSite.getPage(); - - // check if the editor is visible in the workbench page - if (workbenchPage.isPartVisible(this)) { - // and then if the page of the editor is visible (not to be confused with - // the workbench page) - return mGraphicalEditorIndex == getActivePage(); - } - - return false; - } - - @Override - protected void initUiRootNode(boolean force) { - // The root UI node is always created, even if there's no corresponding XML node. - if (mUiRootNode == null || force) { - // get the target data from the opened file (and its project) - AndroidTargetData data = getTargetData(); - - Document doc = null; - if (mUiRootNode != null) { - doc = mUiRootNode.getXmlDocument(); - } - - DocumentDescriptor desc; - if (data == null) { - desc = new DocumentDescriptor("temp", null /*children*/); - } else { - desc = data.getLayoutDescriptors().getDescriptor(); - } - - // get the descriptors from the data. - mUiRootNode = (UiDocumentNode) desc.createUiNode(); - mUiRootNode.setEditor(this); - - onDescriptorsChanged(doc); - } - } - - private void onDescriptorsChanged(Document document) { - if (document != null) { - mUiRootNode.loadFromXmlNode(document); - } else { - mUiRootNode.reloadFromXmlNode(mUiRootNode.getXmlDocument()); - } - - if (mOutline != null) { - mOutline.reloadModel(); - } - - if (mGraphicalEditor != null) { - mGraphicalEditor.reloadEditor(); - mGraphicalEditor.reloadPalette(); - mGraphicalEditor.recomputeLayout(); - } - } - - /** - * Handles a new input, and update the part name. - * @param input the new input. - */ - private void handleNewInput(IEditorInput input) { - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput) input; - IFile file = fileInput.getFile(); - setPartName(String.format("%1$s", - file.getName())); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutReloadMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutReloadMonitor.java deleted file mode 100644 index cf20288..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutReloadMonitor.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolder; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IResourceEventListener; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResourceDelta; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Monitor for file changes triggering a layout redraw. - */ -public final class LayoutReloadMonitor implements IFileListener, IResourceEventListener { - - // singleton, enforced by private constructor. - private final static LayoutReloadMonitor sThis = new LayoutReloadMonitor(); - - /** - * Map of listeners by IProject. - */ - private final Map<IProject, List<ILayoutReloadListener>> mListenerMap = - new HashMap<IProject, List<ILayoutReloadListener>>(); - - private final static int CHANGE_CODE = 0; - private final static int CHANGE_RESOURCES = 1; - private final static int CHANGE_R = 2; - private final static int CHANGE_COUNT = 3; - /** - * List of projects having received a file change. the boolean[] contains 3 values: - * <ul><li>CHANGE_CODE: code change flag.</li> - * <li>CHANGE_RESOURCES: resource change flag.</li> - * <li>CHANGE_R: R clas change flag</li></ul> - */ - private final Map<IProject, boolean[]> mChangedProjects = new HashMap<IProject, boolean[]>(); - - /** - * Classes which implement this interface provide a method to respond to resource changes - * triggering a layout redraw - */ - public interface ILayoutReloadListener { - /** - * Sent when the layout needs to be redrawn - * @param codeChange The trigger happened due to a code change. - * @param rChange The trigger happened due to a change in the R class. - * @param resChange The trigger happened due to a resource change. - */ - void reloadLayout(boolean codeChange, boolean rChange, boolean resChange); - } - - /** - * Returns the single instance of {@link LayoutReloadMonitor}. - */ - public static LayoutReloadMonitor getMonitor() { - return sThis; - } - - private LayoutReloadMonitor() { - ResourceMonitor monitor = ResourceMonitor.getMonitor(); - monitor.addFileListener(this, IResourceDelta.ADDED | IResourceDelta.CHANGED); - monitor.addResourceEventListener(this); - } - - /** - * Adds a listener for a given {@link IProject}. - * @param project - * @param listener - */ - public void addListener(IProject project, ILayoutReloadListener listener) { - synchronized (mListenerMap) { - List<ILayoutReloadListener> list = mListenerMap.get(project); - if (list == null) { - list = new ArrayList<ILayoutReloadListener>(); - mListenerMap.put(project, list); - } - - list.add(listener); - } - } - - /** - * Removes a listener for a given {@link IProject}. - * @param project - * @param listener - */ - public void removeListener(IProject project, ILayoutReloadListener listener) { - synchronized (mListenerMap) { - List<ILayoutReloadListener> list = mListenerMap.get(project); - if (list != null) { - list.remove(listener); - } - } - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener#fileChanged(org.eclipse.core.resources.IFile, org.eclipse.core.resources.IMarkerDelta[], int) - * - * Callback for ResourceMonitor.IFileListener. Called when a file changed. - * This records the changes for each project, but does not notify listeners. - * @see #resourceChangeEventEnd - */ - public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { - // get the file project - IProject project = file.getProject(); - - // if this project has already been marked as modified, we do nothing. - boolean[] changeFlags = mChangedProjects.get(project); - if (changeFlags != null && changeFlags[CHANGE_CODE] && changeFlags[CHANGE_RESOURCES] && - changeFlags[CHANGE_R]) { - return; - } - - // now check that the file is *NOT* a layout file (those automatically trigger a layout - // reload and we don't want to do it twice. - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); - if (resFolder != null) { - if (resFolder.getType() != ResourceFolderType.LAYOUT) { - // this is a resource change! - if (changeFlags == null) { - changeFlags = new boolean[CHANGE_COUNT]; - mChangedProjects.put(project, changeFlags); - } - - changeFlags[CHANGE_RESOURCES] = true; - } - } else if (AndroidConstants.EXT_CLASS.equals(file.getFileExtension())) { - if (file.getName().matches("R[\\$\\.](.*)")) { - // this is a R change! - if (changeFlags == null) { - changeFlags = new boolean[CHANGE_COUNT]; - mChangedProjects.put(project, changeFlags); - } - - changeFlags[CHANGE_R] = true; - } else { - // this is a code change! - if (changeFlags == null) { - changeFlags = new boolean[CHANGE_COUNT]; - mChangedProjects.put(project, changeFlags); - } - - changeFlags[CHANGE_CODE] = true; - } - } - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IResourceEventListener#resourceChangeEventStart() - * - * Callback for ResourceMonitor.IResourceEventListener. Called at the beginning of a resource - * change event. This is called once, while fileChanged can be called several times. - * - */ - public void resourceChangeEventStart() { - // nothing to be done here, it all happens in the resourceChangeEventEnd - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IResourceEventListener#resourceChangeEventEnd() - * - * Callback for ResourceMonitor.IResourceEventListener. Called at the end of a resource - * change event. This is where we notify the listeners. - */ - public void resourceChangeEventEnd() { - // for each IProject that was changed, we notify all the listeners. - synchronized (mListenerMap) { - for (Entry<IProject, boolean[]> project : mChangedProjects.entrySet()) { - List<ILayoutReloadListener> listeners = mListenerMap.get(project.getKey()); - - boolean[] flags = project.getValue(); - - if (listeners != null) { - for (ILayoutReloadListener listener : listeners) { - listener.reloadLayout(flags[CHANGE_CODE], flags[CHANGE_R], - flags[CHANGE_RESOURCES]); - } - } - } - } - - // empty the list. - mChangedProjects.clear(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutSourceViewerConfig.java deleted file mode 100644 index 1aa1f4c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutSourceViewerConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - - -import com.android.ide.eclipse.editors.AndroidSourceViewerConfig; - -/** - * Source Viewer Configuration that calls in LayoutContentAssist. - */ -public class LayoutSourceViewerConfig extends AndroidSourceViewerConfig { - - public LayoutSourceViewerConfig() { - super(new LayoutContentAssist()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/MatchingStrategy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/MatchingStrategy.java deleted file mode 100644 index bb075c2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/MatchingStrategy.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.editors.resources.manager.ResourceFolder; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; - -import org.eclipse.core.resources.IFile; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorMatchingStrategy; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.FileEditorInput; - -/** - * Matching strategy for the Layout Editor. This is used to open all configurations of a layout - * in the same editor. - */ -public class MatchingStrategy implements IEditorMatchingStrategy { - - public boolean matches(IEditorReference editorRef, IEditorInput input) { - // first check that the file being opened is a layout file. - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - - // get the IFile object and check it's in one of the layout folders. - IFile iFile = fileInput.getFile(); - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(iFile); - - // if it's a layout, we know check the name of the fileInput against the name of the - // file being currently edited by the editor since those are independent of the config. - if (resFolder != null && resFolder.getType() == ResourceFolderType.LAYOUT) { - try { - IEditorInput editorInput = editorRef.getEditorInput(); - if (editorInput instanceof FileEditorInput) { - FileEditorInput editorFileInput = (FileEditorInput)editorInput; - IFile editorIFile = editorFileInput.getFile(); - - return editorIFile.getProject().equals(iFile.getProject()) - && editorIFile.getName().equals(iFile.getName()); - } - } catch (PartInitException e) { - // we do nothing, we'll just return false. - } - } - } - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/PaletteFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/PaletteFactory.java deleted file mode 100644 index 94df28f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/PaletteFactory.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; - -import org.eclipse.gef.palette.PaletteDrawer; -import org.eclipse.gef.palette.PaletteGroup; -import org.eclipse.gef.palette.PaletteRoot; -import org.eclipse.gef.palette.PaletteTemplateEntry; - -import java.util.List; - -/** - * Factory that creates the palette for the {@link GraphicalLayoutEditor}. - */ -public class PaletteFactory { - - /** Static factory, nothing to instantiate here. */ - private PaletteFactory() { - } - - public static PaletteRoot createPaletteRoot(PaletteRoot currentPalette, - AndroidTargetData targetData) { - - if (currentPalette == null) { - currentPalette = new PaletteRoot(); - } - - for (int n = currentPalette.getChildren().size() - 1; n >= 0; n--) { - currentPalette.getChildren().remove(n); - } - - if (targetData != null) { - addTools(currentPalette); - addViews(currentPalette, "Layouts", - targetData.getLayoutDescriptors().getLayoutDescriptors()); - addViews(currentPalette, "Views", - targetData.getLayoutDescriptors().getViewDescriptors()); - } - - return currentPalette; - } - - private static void addTools(PaletteRoot paletteRoot) { - PaletteGroup group = new PaletteGroup("Tools"); - - // Default tools: selection. - // Do not use the MarqueeToolEntry since we don't support multiple selection. - /* -- Do not put the selection tool. It's the unique tool so it looks useless. - Leave this piece of code here in case we want it back later. - PanningSelectionToolEntry entry = new PanningSelectionToolEntry(); - group.add(entry); - paletteRoot.setDefaultEntry(entry); - */ - - paletteRoot.add(group); - } - - private static void addViews(PaletteRoot paletteRoot, String groupName, - List<ElementDescriptor> descriptors) { - PaletteDrawer group = new PaletteDrawer(groupName); - - for (ElementDescriptor desc : descriptors) { - PaletteTemplateEntry entry = new PaletteTemplateEntry( - desc.getUiName(), // label - desc.getTooltip(), // short description - desc, // template - desc.getImageDescriptor(), // small icon - desc.getImageDescriptor() // large icon - ); - - group.add(entry); - } - - paletteRoot.add(group); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java deleted file mode 100644 index 81fd2ed..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.ide.eclipse.editors.resources.manager.ProjectClassLoader; -import com.android.ide.eclipse.editors.resources.manager.ProjectResources; -import com.android.layoutlib.api.IProjectCallback; - -import org.eclipse.core.resources.IProject; - -import java.lang.reflect.Constructor; -import java.util.HashMap; - -/** - * Loader for Android Project class in order to use them in the layout editor. - */ -public final class ProjectCallback implements IProjectCallback { - - private final HashMap<String, Class<?>> mLoadedClasses = new HashMap<String, Class<?>>(); - private final IProject mProject; - private final ClassLoader mParentClassLoader; - private final ProjectResources mProjectRes; - private boolean mUsed = false; - private String mNamespace; - - ProjectCallback(ClassLoader classLoader, ProjectResources projectRes, IProject project) { - mParentClassLoader = classLoader; - mProjectRes = projectRes; - mProject = project; - } - - - /** - * {@inheritDoc} - * - * This implementation goes through the output directory of the Eclipse project and loads the - * <code>.class</code> file directly. - */ - @SuppressWarnings("unchecked") - public Object loadView(String className, Class[] constructorSignature, - Object[] constructorParameters) - throws ClassNotFoundException, Exception { - - // look for a cached version - Class<?> clazz = mLoadedClasses.get(className); - if (clazz != null) { - return instantiateClass(clazz, constructorSignature, constructorParameters); - } - - // load the class. - ProjectClassLoader loader = new ProjectClassLoader(mParentClassLoader, mProject); - try { - clazz = loader.loadClass(className); - - if (clazz != null) { - mUsed = true; - mLoadedClasses.put(className, clazz); - return instantiateClass(clazz, constructorSignature, constructorParameters); - } - } catch (Error e) { - // Log this error with the class name we're trying to load and abort. - AdtPlugin.log(e, "ProjectCallback.loadView failed to find class %1$s", className); //$NON-NLS-1$ - } - - return null; - } - - /** - * {@inheritDoc} - * - * Returns the namespace for the project. The namespace contains a standard part + the - * application package. - */ - public String getNamespace() { - if (mNamespace == null) { - AndroidManifestHelper manifest = new AndroidManifestHelper(mProject); - String javaPackage = manifest.getPackageName(); - - mNamespace = String.format(AndroidConstants.NS_CUSTOM_RESOURCES, javaPackage); - } - - return mNamespace; - } - - /* - * (non-Javadoc) - * @see com.android.layoutlib.api.IProjectCallback#resolveResourceValue(int) - */ - public String[] resolveResourceValue(int id) { - if (mProjectRes != null) { - return mProjectRes.resolveResourceValue(id); - } - - return null; - } - - /* - * (non-Javadoc) - * @see com.android.layoutlib.api.IProjectCallback#resolveResourceValue(int[]) - */ - public String resolveResourceValue(int[] id) { - if (mProjectRes != null) { - return mProjectRes.resolveResourceValue(id); - } - - return null; - } - - /* - * (non-Javadoc) - * @see com.android.layoutlib.api.IProjectCallback#getResourceValue(java.lang.String, java.lang.String) - */ - public Integer getResourceValue(String type, String name) { - if (mProjectRes != null) { - return mProjectRes.getResourceValue(type, name); - } - - return null; - } - - /** - * Returns whether the loader has received requests to load custom views. - * <p/>This allows to efficiently only recreate when needed upon code change in the project. - */ - boolean isUsed() { - return mUsed; - } - - /** - * Instantiate a class object, using a specific constructor and parameters. - * @param clazz the class to instantiate - * @param constructorSignature the signature of the constructor to use - * @param constructorParameters the parameters to use in the constructor. - * @return A new class object, created using a specific constructor and parameters. - * @throws Exception - */ - @SuppressWarnings("unchecked") - private Object instantiateClass(Class<?> clazz, Class[] constructorSignature, - Object[] constructorParameters) throws Exception { - Constructor<?> constructor = clazz.getConstructor(constructorSignature); - constructor.setAccessible(true); - return constructor.newInstance(constructorParameters); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java deleted file mode 100644 index 3e0f5d8..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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.editors.layout; - -import com.android.ide.eclipse.common.EclipseUiHelper; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.layout.parts.UiDocumentTreeEditPart; -import com.android.ide.eclipse.editors.layout.parts.UiElementTreeEditPart; -import com.android.ide.eclipse.editors.layout.parts.UiElementTreeEditPartFactory; -import com.android.ide.eclipse.editors.layout.parts.UiLayoutTreeEditPart; -import com.android.ide.eclipse.editors.layout.parts.UiViewTreeEditPart; -import com.android.ide.eclipse.editors.ui.tree.CopyCutAction; -import com.android.ide.eclipse.editors.ui.tree.PasteAction; -import com.android.ide.eclipse.editors.ui.tree.UiActions; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.gef.EditPartViewer; -import org.eclipse.gef.ui.parts.ContentOutlinePage; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; -import org.eclipse.ui.IActionBars; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** - * Implementation of the {@link ContentOutlinePage} to display {@link UiElementNode}. - */ -class UiContentOutlinePage extends ContentOutlinePage { - - private GraphicalLayoutEditor mEditor; - - private Action mAddAction; - private Action mDeleteAction; - private Action mUpAction; - private Action mDownAction; - - private UiOutlineActions mUiActions = new UiOutlineActions(); - - public UiContentOutlinePage(GraphicalLayoutEditor editor, final EditPartViewer viewer) { - super(viewer); - mEditor = editor; - IconFactory factory = IconFactory.getInstance(); - - mAddAction = new Action("Add...") { - @Override - public void run() { - List<UiElementNode> nodes = getModelSelections(); - UiElementNode node = nodes != null && nodes.size() > 0 ? nodes.get(0) : null; - - mUiActions.doAdd(node, viewer.getControl().getShell()); - } - }; - mAddAction.setToolTipText("Adds a new element."); - mAddAction.setImageDescriptor(factory.getImageDescriptor("add")); //$NON-NLS-1$ - - mDeleteAction = new Action("Remove...") { - @Override - public void run() { - List<UiElementNode> nodes = getModelSelections(); - - mUiActions.doRemove(nodes, viewer.getControl().getShell()); - } - }; - mDeleteAction.setToolTipText("Removes an existing selected element."); - mDeleteAction.setImageDescriptor(factory.getImageDescriptor("delete")); //$NON-NLS-1$ - - mUpAction = new Action("Up") { - @Override - public void run() { - List<UiElementNode> nodes = getModelSelections(); - - mUiActions.doUp(nodes); - } - }; - mUpAction.setToolTipText("Moves the selected element up"); - mUpAction.setImageDescriptor(factory.getImageDescriptor("up")); //$NON-NLS-1$ - - mDownAction = new Action("Down") { - @Override - public void run() { - List<UiElementNode> nodes = getModelSelections(); - - mUiActions.doDown(nodes); - } - }; - mDownAction.setToolTipText("Moves the selected element down"); - mDownAction.setImageDescriptor(factory.getImageDescriptor("down")); //$NON-NLS-1$ - - // all actions disabled by default. - mAddAction.setEnabled(false); - mDeleteAction.setEnabled(false); - mUpAction.setEnabled(false); - mDownAction.setEnabled(false); - - addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - ISelection selection = event.getSelection(); - - // the selection is never empty. The least it'll contain is the - // UiDocumentTreeEditPart object. - if (selection instanceof StructuredSelection) { - StructuredSelection structSel = (StructuredSelection)selection; - - if (structSel.size() == 1 && - structSel.getFirstElement() instanceof UiDocumentTreeEditPart) { - mDeleteAction.setEnabled(false); - mUpAction.setEnabled(false); - mDownAction.setEnabled(false); - } else { - mDeleteAction.setEnabled(true); - mUpAction.setEnabled(true); - mDownAction.setEnabled(true); - } - - // the "add" button is always enabled, in order to be able to set the - // initial root node - mAddAction.setEnabled(true); - } - } - }); - } - - - /* (non-Javadoc) - * @see org.eclipse.ui.part.IPage#createControl(org.eclipse.swt.widgets.Composite) - */ - @Override - public void createControl(Composite parent) { - // create outline viewer page - getViewer().createControl(parent); - - // configure outline viewer - getViewer().setEditPartFactory(new UiElementTreeEditPartFactory()); - - setupOutline(); - setupContextMenu(); - setupTooltip(); - setupDoubleClick(); - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.part.Page#setActionBars(org.eclipse.ui.IActionBars) - * - * Called automatically after createControl - */ - @Override - public void setActionBars(IActionBars actionBars) { - IToolBarManager toolBarManager = actionBars.getToolBarManager(); - toolBarManager.add(mAddAction); - toolBarManager.add(mDeleteAction); - toolBarManager.add(new Separator()); - toolBarManager.add(mUpAction); - toolBarManager.add(mDownAction); - - IMenuManager menuManager = actionBars.getMenuManager(); - menuManager.add(mAddAction); - menuManager.add(mDeleteAction); - menuManager.add(new Separator()); - menuManager.add(mUpAction); - menuManager.add(mDownAction); - } - - /* (non-Javadoc) - * @see org.eclipse.ui.part.IPage#dispose() - */ - @Override - public void dispose() { - breakConnectionWithEditor(); - - // dispose - super.dispose(); - } - - /* (non-Javadoc) - * @see org.eclipse.ui.part.IPage#getControl() - */ - @Override - public Control getControl() { - return getViewer().getControl(); - } - - void setNewEditor(GraphicalLayoutEditor editor) { - mEditor = editor; - setupOutline(); - } - - void breakConnectionWithEditor() { - // unhook outline viewer - mEditor.getSelectionSynchronizer().removeViewer(getViewer()); - } - - private void setupOutline() { - getViewer().setEditDomain(mEditor.getEditDomain()); - - // hook outline viewer - mEditor.getSelectionSynchronizer().addViewer(getViewer()); - - // initialize outline viewer with model - getViewer().setContents(mEditor.getModel()); - } - - private void setupContextMenu() { - MenuManager menuManager = new MenuManager(); - menuManager.setRemoveAllWhenShown(true); - menuManager.addMenuListener(new IMenuListener() { - /** - * The menu is about to be shown. The menu manager has already been - * requested to remove any existing menu item. This method gets the - * tree selection and if it is of the appropriate type it re-creates - * the necessary actions. - */ - public void menuAboutToShow(IMenuManager manager) { - List<UiElementNode> selected = getModelSelections(); - - if (selected != null) { - doCreateMenuAction(manager, selected); - return; - } - doCreateMenuAction(manager, null /* ui_node */); - } - }); - Control control = getControl(); - Menu contextMenu = menuManager.createContextMenu(control); - control.setMenu(contextMenu); - } - - /** - * Adds the menu actions to the context menu when the given UI node is selected in - * the tree view. - * - * @param manager The context menu manager - * @param selected The UI node selected in the tree. Can be null, in which case the root - * is to be modified. - */ - private void doCreateMenuAction(IMenuManager manager, List<UiElementNode> selected) { - - if (selected != null) { - boolean hasXml = false; - for (UiElementNode uiNode : selected) { - if (uiNode.getXmlNode() != null) { - hasXml = true; - break; - } - } - - if (hasXml) { - manager.add(new CopyCutAction(mEditor.getLayoutEditor(), mEditor.getClipboard(), - null, selected, true /* cut */)); - manager.add(new CopyCutAction(mEditor.getLayoutEditor(), mEditor.getClipboard(), - null, selected, false /* cut */)); - - // Can't paste with more than one element selected (the selection is the target) - if (selected.size() <= 1) { - // Paste is not valid if it would add a second element on a terminal element - // which parent is a document -- an XML document can only have one child. This - // means paste is valid if the current UI node can have children or if the parent - // is not a document. - UiElementNode ui_root = selected.get(0).getUiRoot(); - if (ui_root.getDescriptor().hasChildren() || - !(ui_root.getUiParent() instanceof UiDocumentNode)) { - manager.add(new PasteAction(mEditor.getLayoutEditor(), - mEditor.getClipboard(), - selected.get(0))); - } - } - manager.add(new Separator()); - } - } - - // Append "add" and "remove" actions. They do the same thing as the add/remove - // buttons on the side. - // - // "Add" makes sense only if there's 0 or 1 item selected since the - // one selected item becomes the target. - if (selected == null || selected.size() <= 1) { - manager.add(mAddAction); - } - - if (selected != null) { - manager.add(mDeleteAction); - manager.add(new Separator()); - - manager.add(mUpAction); - manager.add(mDownAction); - } - - if (selected != null && selected.size() == 1) { - manager.add(new Separator()); - - Action propertiesAction = new Action("Properties") { - @Override - public void run() { - EclipseUiHelper.showView(EclipseUiHelper.PROPERTY_SHEET_VIEW_ID, - true /* activate */); - } - }; - propertiesAction.setToolTipText("Displays properties of the selected element."); - manager.add(propertiesAction); - } - } - - /** - * Updates the outline view with the model of the {@link GraphicalLayoutEditor}. - * <p/> - * This attemps to preserve the selection, if any. - */ - public void reloadModel() { - // Attemps to preserve the UiNode selection, if any - List<UiElementNode> uiNodes = null; - try { - // get current selection using the model rather than the edit part as - // reloading the content may change the actual edit part. - uiNodes = getModelSelections(); - - // perform the update - getViewer().setContents(mEditor.getModel()); - - } finally { - // restore selection - if (uiNodes != null) { - setModelSelection(uiNodes.get(0)); - } - } - } - - /** - * Returns the currently selected element, if any, in the viewer. - * This returns the viewer's elements (i.e. an {@link UiElementTreeEditPart}) - * and not the underlying model node. - * <p/> - * When there is no actual selection, this might still return the root node, - * which is of type {@link UiDocumentTreeEditPart}. - */ - @SuppressWarnings("unchecked") - private List<UiElementTreeEditPart> getViewerSelections() { - ISelection selection = getSelection(); - if (selection instanceof StructuredSelection) { - StructuredSelection structuredSelection = (StructuredSelection)selection; - - if (structuredSelection.size() > 0) { - ArrayList<UiElementTreeEditPart> selected = new ArrayList<UiElementTreeEditPart>(); - - for (Iterator it = structuredSelection.iterator(); it.hasNext(); ) { - Object selectedObj = it.next(); - - if (selectedObj instanceof UiElementTreeEditPart) { - selected.add((UiElementTreeEditPart) selectedObj); - } - } - - return selected.size() > 0 ? selected : null; - } - } - - return null; - } - - /** - * Returns the currently selected model element, which is either an - * {@link UiViewTreeEditPart} or an {@link UiLayoutTreeEditPart}. - * <p/> - * Returns null if there is no selection or if the implicit root is "selected" - * (which actually represents the lack of a real element selection.) - */ - private List<UiElementNode> getModelSelections() { - - List<UiElementTreeEditPart> parts = getViewerSelections(); - - if (parts != null) { - ArrayList<UiElementNode> selected = new ArrayList<UiElementNode>(); - - for (UiElementTreeEditPart part : parts) { - if (part instanceof UiViewTreeEditPart || part instanceof UiLayoutTreeEditPart) { - selected.add((UiElementNode) part.getModel()); - } - } - - return selected.size() > 0 ? selected : null; - } - - return null; - } - - /** - * Selects the corresponding edit part in the tree viewer. - */ - private void setViewerSelection(UiElementTreeEditPart selectedPart) { - if (selectedPart != null && !(selectedPart instanceof UiDocumentTreeEditPart)) { - LinkedList<UiElementTreeEditPart> segments = new LinkedList<UiElementTreeEditPart>(); - for (UiElementTreeEditPart part = selectedPart; - !(part instanceof UiDocumentTreeEditPart); - part = (UiElementTreeEditPart) part.getParent()) { - segments.add(0, part); - } - setSelection(new TreeSelection(new TreePath(segments.toArray()))); - } - } - - /** - * Selects the corresponding model element in the tree viewer. - */ - private void setModelSelection(UiElementNode uiNodeToSelect) { - if (uiNodeToSelect != null) { - - // find an edit part that has the requested model element - UiElementTreeEditPart part = findPartForModel( - (UiElementTreeEditPart) getViewer().getContents(), - uiNodeToSelect); - - // if we found a part, select it and reveal it - if (part != null) { - setViewerSelection(part); - getViewer().reveal(part); - } - } - } - - /** - * Utility method that tries to find an edit part that matches a given model UI node. - * - * @param rootPart The root of the viewer edit parts - * @param uiNode The UI node model to find - * @return The part that matches the model or null if it's not in the sub tree. - */ - private UiElementTreeEditPart findPartForModel(UiElementTreeEditPart rootPart, - UiElementNode uiNode) { - if (rootPart.getModel() == uiNode) { - return rootPart; - } - - for (Object part : rootPart.getChildren()) { - if (part instanceof UiElementTreeEditPart) { - UiElementTreeEditPart found = findPartForModel( - (UiElementTreeEditPart) part, uiNode); - if (found != null) { - return found; - } - } - } - - return null; - } - - /** - * Sets up a custom tooltip when hovering over tree items. - * <p/> - * The tooltip will display the element's javadoc, if any, or the item's getText otherwise. - */ - private void setupTooltip() { - final Tree tree = (Tree) getControl(); - - /* - * Reference: - * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet125.java?view=markup - */ - - final Listener listener = new Listener() { - Shell tip = null; - Label label = null; - - public void handleEvent(Event event) { - switch(event.type) { - case SWT.Dispose: - case SWT.KeyDown: - case SWT.MouseExit: - case SWT.MouseDown: - case SWT.MouseMove: - if (tip != null) { - tip.dispose(); - tip = null; - label = null; - } - break; - case SWT.MouseHover: - if (tip != null) { - tip.dispose(); - tip = null; - label = null; - } - - String tooltip = null; - - TreeItem item = tree.getItem(new Point(event.x, event.y)); - if (item != null) { - Object data = item.getData(); - if (data instanceof UiElementTreeEditPart) { - Object model = ((UiElementTreeEditPart) data).getModel(); - if (model instanceof UiElementNode) { - tooltip = ((UiElementNode) model).getDescriptor().getTooltip(); - } - } - - if (tooltip == null) { - tooltip = item.getText(); - } else { - tooltip = item.getText() + ":\r" + tooltip; - } - } - - - if (tooltip != null) { - Shell shell = tree.getShell(); - Display display = tree.getDisplay(); - - tip = new Shell(shell, SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL); - tip.setBackground(display .getSystemColor(SWT.COLOR_INFO_BACKGROUND)); - FillLayout layout = new FillLayout(); - layout.marginWidth = 2; - tip.setLayout(layout); - label = new Label(tip, SWT.NONE); - label.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); - label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); - label.setData("_TABLEITEM", item); - label.setText(tooltip); - label.addListener(SWT.MouseExit, this); - label.addListener(SWT.MouseDown, this); - Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT); - Rectangle rect = item.getBounds(0); - Point pt = tree.toDisplay(rect.x, rect.y); - tip.setBounds(pt.x, pt.y, size.x, size.y); - tip.setVisible(true); - } - } - } - }; - - tree.addListener(SWT.Dispose, listener); - tree.addListener(SWT.KeyDown, listener); - tree.addListener(SWT.MouseMove, listener); - tree.addListener(SWT.MouseHover, listener); - } - - /** - * Sets up double-click action on the tree. - * <p/> - * By default, double-click (a.k.a. "default selection") on a valid list item will - * show the property view. - */ - private void setupDoubleClick() { - final Tree tree = (Tree) getControl(); - - tree.addListener(SWT.DefaultSelection, new Listener() { - public void handleEvent(Event event) { - EclipseUiHelper.showView(EclipseUiHelper.PROPERTY_SHEET_VIEW_ID, - true /* activate */); - } - }); - } - - // --------------- - - private class UiOutlineActions extends UiActions { - - @Override - protected UiDocumentNode getRootNode() { - return mEditor.getModel(); // this is LayoutEditor.getUiRootNode() - } - - // Select the new item - @Override - protected void selectUiNode(UiElementNode uiNodeToSelect) { - setModelSelection(uiNodeToSelect); - } - - @Override - public void commitPendingXmlChanges() { - // Pass. There is nothing to commit before the XML is changed here. - } - - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiElementPullParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiElementPullParser.java deleted file mode 100644 index b0e6fdb..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiElementPullParser.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.layoutlib.api.IXmlPullParser; - -import org.w3c.dom.Node; -import org.xmlpull.v1.XmlPullParserException; - -import java.util.ArrayList; -import java.util.List; - -/** - * {@link IXmlPullParser} implementation on top of {@link UiElementNode}. - * <p/>It's designed to work on layout files, and will most likely not work on other resource - * files. - */ -public final class UiElementPullParser extends BasePullParser { - - private final ArrayList<UiElementNode> mNodeStack = new ArrayList<UiElementNode>(); - private UiElementNode mRoot; - - public UiElementPullParser(UiElementNode top) { - super(); - mRoot = top; - push(mRoot); - } - - private UiElementNode getCurrentNode() { - if (mNodeStack.size() > 0) { - return mNodeStack.get(mNodeStack.size()-1); - } - - return null; - } - - private Node getAttribute(int i) { - if (mParsingState != START_TAG) { - throw new IndexOutOfBoundsException(); - } - - // get the current uiNode - UiElementNode uiNode = getCurrentNode(); - - // get its xml node - Node xmlNode = uiNode.getXmlNode(); - - if (xmlNode != null) { - return xmlNode.getAttributes().item(i); - } - - return null; - } - - private void push(UiElementNode node) { - mNodeStack.add(node); - } - - private UiElementNode pop() { - return mNodeStack.remove(mNodeStack.size()-1); - } - - // ------------- IXmlPullParser -------- - - /** - * {@inheritDoc} - * - * This implementation returns the underlying DOM node. - */ - public Object getViewKey() { - return getCurrentNode(); - } - - // ------------- XmlPullParser -------- - - public String getPositionDescription() { - return "XML DOM element depth:" + mNodeStack.size(); - } - - public int getAttributeCount() { - UiElementNode node = getCurrentNode(); - if (node != null) { - return node.getUiAttributes().size(); - } - - return 0; - } - - public String getAttributeName(int i) { - Node attribute = getAttribute(i); - if (attribute != null) { - return attribute.getLocalName(); - } - - return null; - } - - public String getAttributeNamespace(int i) { - Node attribute = getAttribute(i); - if (attribute != null) { - return attribute.getNamespaceURI(); - } - return ""; //$NON-NLS-1$ - } - - public String getAttributePrefix(int i) { - Node attribute = getAttribute(i); - if (attribute != null) { - return attribute.getPrefix(); - } - return null; - } - - public String getAttributeValue(int i) { - Node attribute = getAttribute(i); - if (attribute != null) { - return attribute.getNodeValue(); - } - - return null; - } - - public String getAttributeValue(String namespace, String localName) { - // get the current uiNode - UiElementNode uiNode = getCurrentNode(); - - // get its xml node - Node xmlNode = uiNode.getXmlNode(); - - if (xmlNode != null) { - Node attribute = xmlNode.getAttributes().getNamedItemNS(namespace, localName); - if (attribute != null) { - return attribute.getNodeValue(); - } - } - - return null; - } - - public int getDepth() { - return mNodeStack.size(); - } - - public String getName() { - if (mParsingState == START_TAG || mParsingState == END_TAG) { - return getCurrentNode().getDescriptor().getXmlLocalName(); - } - - return null; - } - - public String getNamespace() { - if (mParsingState == START_TAG || mParsingState == END_TAG) { - return getCurrentNode().getDescriptor().getNamespace(); - } - - return null; - } - - public String getPrefix() { - if (mParsingState == START_TAG || mParsingState == END_TAG) { - // FIXME will NEVER work - if (getCurrentNode().getDescriptor().getXmlLocalName().startsWith("android:")) { //$NON-NLS-1$ - return "android"; //$NON-NLS-1$ - } - } - - return null; - } - - public boolean isEmptyElementTag() throws XmlPullParserException { - if (mParsingState == START_TAG) { - return getCurrentNode().getUiChildren().size() == 0; - } - - throw new XmlPullParserException("Call to isEmptyElementTag while not in START_TAG", - this, null); - } - - @Override - public void onNextFromStartDocument() { - onNextFromStartTag(); - } - - @Override - public void onNextFromStartTag() { - // get the current node, and look for text or children (children first) - UiElementNode node = getCurrentNode(); - List<UiElementNode> children = node.getUiChildren(); - if (children.size() > 0) { - // move to the new child, and don't change the state. - push(children.get(0)); - - // in case the current state is CURRENT_DOC, we set the proper state. - mParsingState = START_TAG; - } else { - if (mParsingState == START_DOCUMENT) { - // this handles the case where there's no node. - mParsingState = END_DOCUMENT; - } else { - mParsingState = END_TAG; - } - } - } - - @Override - public void onNextFromEndTag() { - // look for a sibling. if no sibling, go back to the parent - UiElementNode node = getCurrentNode(); - node = node.getUiNextSibling(); - if (node != null) { - // to go to the sibling, we need to remove the current node, - pop(); - // and add its sibling. - push(node); - mParsingState = START_TAG; - } else { - // move back to the parent - pop(); - - // we have only one element left (mRoot), then we're done with the document. - if (mNodeStack.size() == 1) { - mParsingState = END_DOCUMENT; - } else { - mParsingState = END_TAG; - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiPropertySheetPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiPropertySheetPage.java deleted file mode 100644 index 8093c90..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiPropertySheetPage.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeItem; -import org.eclipse.ui.views.properties.PropertySheetEntry; -import org.eclipse.ui.views.properties.PropertySheetPage; - -/** - * A customized property sheet page for the graphical layout editor. - * <p/> - * Currently it just provides a custom tooltip to display attributes javadocs. - */ -public class UiPropertySheetPage extends PropertySheetPage { - - - public UiPropertySheetPage() { - super(); - } - - @Override - public void createControl(Composite parent) { - super.createControl(parent); - - setupTooltip(); - } - - /** - * Sets up a custom tooltip when hovering over tree items. - * <p/> - * The tooltip will display the element's javadoc, if any, or the item's getText otherwise. - */ - private void setupTooltip() { - final Tree tree = (Tree) getControl(); - - /* - * Reference: - * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet125.java?view=markup - */ - - final Listener listener = new Listener() { - Shell tip = null; - Label label = null; - - public void handleEvent(Event event) { - switch(event.type) { - case SWT.Dispose: - case SWT.KeyDown: - case SWT.MouseExit: - case SWT.MouseDown: - case SWT.MouseMove: - if (tip != null) { - tip.dispose(); - tip = null; - label = null; - } - break; - case SWT.MouseHover: - if (tip != null) { - tip.dispose(); - tip = null; - label = null; - } - - String tooltip = null; - - TreeItem item = tree.getItem(new Point(event.x, event.y)); - if (item != null) { - Object data = item.getData(); - if (data instanceof PropertySheetEntry) { - tooltip = ((PropertySheetEntry) data).getDescription(); - } - - if (tooltip == null) { - tooltip = item.getText(); - } else { - tooltip = item.getText() + ":\r" + tooltip; - } - } - - if (tooltip != null) { - Shell shell = tree.getShell(); - Display display = tree.getDisplay(); - - tip = new Shell(shell, SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL); - tip.setBackground(display .getSystemColor(SWT.COLOR_INFO_BACKGROUND)); - FillLayout layout = new FillLayout(); - layout.marginWidth = 2; - tip.setLayout(layout); - label = new Label(tip, SWT.NONE); - label.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); - label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); - label.setData("_TABLEITEM", item); - label.setText(tooltip); - label.addListener(SWT.MouseExit, this); - label.addListener(SWT.MouseDown, this); - Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT); - Rectangle rect = item.getBounds(0); - Point pt = tree.toDisplay(rect.x, rect.y); - tip.setBounds(pt.x, pt.y, size.x, size.y); - tip.setVisible(true); - } - } - } - }; - - tree.addListener(SWT.Dispose, listener); - tree.addListener(SWT.KeyDown, listener); - tree.addListener(SWT.MouseMove, listener); - tree.addListener(SWT.MouseHover, listener); - - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java deleted file mode 100644 index e62ab69..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/WidgetPullParser.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; -import com.android.layoutlib.api.IXmlPullParser; -import com.android.sdklib.SdkConstants; - -import org.xmlpull.v1.XmlPullParserException; - -/** - * {@link IXmlPullParser} implementation to render android widget bitmap. - * <p/>The parser emulates a layout that contains just one widget, described by the - * {@link ViewElementDescriptor} passed in the constructor. - */ -public class WidgetPullParser extends BasePullParser { - - private final ViewElementDescriptor mDescriptor; - private String[][] mAttributes = new String[][] { - { "text", null }, - { "layout_width", "wrap_content" }, - { "layout_height", "wrap_content" }, - }; - - public WidgetPullParser(ViewElementDescriptor descriptor) { - mDescriptor = descriptor; - - String[] segments = mDescriptor.getCanonicalClassName().split(AndroidConstants.RE_DOT); - mAttributes[0][1] = segments[segments.length-1]; - } - - public Object getViewKey() { - // we need a viewKey or the ILayoutResult will not contain any ILayoutViewInfo - return mDescriptor; - } - - public int getAttributeCount() { - return mAttributes.length; // text attribute - } - - public String getAttributeName(int index) { - if (index < mAttributes.length) { - return mAttributes[index][0]; - } - - return null; - } - - public String getAttributeNamespace(int index) { - return SdkConstants.NS_RESOURCES; - } - - public String getAttributePrefix(int index) { - // pass - return null; - } - - public String getAttributeValue(int index) { - if (index < mAttributes.length) { - return mAttributes[index][1]; - } - - return null; - } - - public String getAttributeValue(String ns, String name) { - if (SdkConstants.NS_RESOURCES.equals(ns)) { - for (String[] attribute : mAttributes) { - if (name.equals(attribute[0])) { - return attribute[1]; - } - } - } - - return null; - } - - public int getDepth() { - // pass - return 0; - } - - public String getName() { - return mDescriptor.getXmlLocalName(); - } - - public String getNamespace() { - // pass - return null; - } - - public String getPositionDescription() { - // pass - return null; - } - - public String getPrefix() { - // pass - return null; - } - - public boolean isEmptyElementTag() throws XmlPullParserException { - if (mParsingState == START_TAG) { - return true; - } - - throw new XmlPullParserException("Call to isEmptyElementTag while not in START_TAG", - this, null); - } - - @Override - public void onNextFromStartDocument() { - // just go to start_tag - mParsingState = START_TAG; - } - - @Override - public void onNextFromStartTag() { - // since we have no children, just go to end_tag - mParsingState = END_TAG; - } - - @Override - public void onNextFromEndTag() { - // just one tag. we are done. - mParsingState = END_DOCUMENT; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/CustomViewDescriptorService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/CustomViewDescriptorService.java deleted file mode 100644 index d5ee2ca..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/CustomViewDescriptorService.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.descriptors; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.resources.ViewClassInfo; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.sdklib.IAndroidTarget; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; - -import java.util.HashMap; -import java.util.List; - -/** - * Service responsible for creating/managing {@link ElementDescriptor} objects for custom - * View classes per project. - * <p/> - * The service provides an on-demand monitoring of custom classes to check for changes. Monitoring - * starts once a request for an {@link ElementDescriptor} object has been done for a specific - * class.<br> - * The monitoring will notify a listen of any changes in the class triggering a change in its - * associated {@link ElementDescriptor} object. - * <p/> - * If the custom class does not exist, no monitoring is put in place to avoid having to listen - * to all class changes in the projects. - * - */ -public final class CustomViewDescriptorService { - - private static CustomViewDescriptorService sThis = new CustomViewDescriptorService(); - - /** - * Map where keys are the project, and values are another map containing all the known - * custom View class for this project. The custom View class are stored in a map - * where the keys are the fully qualified class name, and the values are their associated - * {@link ElementDescriptor}. - */ - private HashMap<IProject, HashMap<String, ElementDescriptor>> mCustomDescriptorMap = - new HashMap<IProject, HashMap<String, ElementDescriptor>>(); - - /** - * TODO will be used to update the ElementDescriptor of the custom view when it - * is modified (either the class itself or its attributes.xml) - */ - @SuppressWarnings("unused") - private ICustomViewDescriptorListener mListener; - - /** - * Classes which implements this interface provide a method that deal with modifications - * in custom View class triggering a change in its associated {@link ViewClassInfo} object. - */ - public interface ICustomViewDescriptorListener { - /** - * Sent when a custom View class has changed and its {@link ElementDescriptor} was modified. - * @param project the project containing the class. - * @param className the fully qualified class name. - * @param descriptor the updated ElementDescriptor. - */ - public void updatedClassInfo(IProject project, String className, ElementDescriptor descriptor); - } - - /** - * Returns the singleton instance of {@link CustomViewDescriptorService}. - */ - public static CustomViewDescriptorService getInstance() { - return sThis; - } - - /** - * Sets the listener receiving custom View class modification notifications. - * @param listener the listener to receive the notifications. - * - * TODO will be used to update the ElementDescriptor of the custom view when it - * is modified (either the class itself or its attributes.xml) - */ - public void setListener(ICustomViewDescriptorListener listener) { - mListener = listener; - } - - /** - * Returns the {@link ElementDescriptor} for a particular project/class. - * <p/> - * If it is the first time the <code>ElementDescriptor</code> is requested, the method - * will check that the specified class is in fact a custom View class. Once this is - * established, a monitoring for that particular class is initiated. Any change will - * trigger a notification to the {@link ICustomViewDescriptorListener}. - * @param project the project containing the class. - * @param fqClassName the fully qualified name of the class. - * @return a <code>ElementDescriptor</code> or <code>null</code> if the class was not - * a custom View class. - */ - public ElementDescriptor getDescriptor(IProject project, String fqClassName) { - // look in the map first - synchronized (mCustomDescriptorMap) { - HashMap<String, ElementDescriptor> map = mCustomDescriptorMap.get(project); - - if (map != null) { - ElementDescriptor descriptor = map.get(fqClassName); - if (descriptor != null) { - return descriptor; - } - } - - // if we step here, it looks like we haven't created it yet. - // First lets check this is in fact a valid type in the project - - try { - // We expect the project to be both opened and of java type (since it's an android - // project), so we can create a IJavaProject object from our IProject. - IJavaProject javaProject = JavaCore.create(project); - - // replace $ by . in the class name - String javaClassName = fqClassName.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ - - // look for the IType object for this class - IType type = javaProject.findType(javaClassName); - if (type != null && type.exists()) { - // the type exists. Let's get the parent class and its ViewClassInfo. - - // get the type hierarchy - ITypeHierarchy hierarchy = type.newSupertypeHierarchy( - new NullProgressMonitor()); - - ElementDescriptor parentDescriptor = getDescriptor( - hierarchy.getSuperclass(type), project, hierarchy); - - if (parentDescriptor != null) { - // we have a valid parent, lets create a new ElementDescriptor. - - ViewElementDescriptor descriptor = new ViewElementDescriptor(fqClassName, - fqClassName, // ui_name - fqClassName, // canonical class name - null, // tooltip - null, // sdk_url - getAttributeDescriptor(type, parentDescriptor), - null, // layout attributes - null, // children - false /* mandatory */); - - synchronized (mCustomDescriptorMap) { - map = mCustomDescriptorMap.get(project); - if (map == null) { - map = new HashMap<String, ElementDescriptor>(); - mCustomDescriptorMap.put(project, map); - } - - map.put(fqClassName, descriptor); - } - - //TODO setup listener on this resource change. - - return descriptor; - } - } - } catch (JavaModelException e) { - // there was an error accessing any of the IType, we'll just return null; - } - } - - - return null; - } - - /** - * Computes (if needed) and returns the {@link ElementDescriptor} for the specified type. - * - * @param type - * @param project - * @param typeHierarchy - * @return A ViewElementDescriptor or null if type or typeHierarchy is null. - */ - private ViewElementDescriptor getDescriptor(IType type, IProject project, - ITypeHierarchy typeHierarchy) { - // check if the type is a built-in View class. - List<ElementDescriptor> builtInList = null; - - Sdk currentSdk = Sdk.getCurrent(); - IAndroidTarget target = currentSdk == null ? null : currentSdk.getTarget(project); - if (target != null) { - AndroidTargetData data = currentSdk.getTargetData(target); - builtInList = data.getLayoutDescriptors().getViewDescriptors(); - } - - // give up if there's no type - if (type == null) { - return null; - } - - String canonicalName = type.getFullyQualifiedName(); - - if (builtInList != null) { - for (ElementDescriptor desc : builtInList) { - if (desc instanceof ViewElementDescriptor) { - ViewElementDescriptor viewDescriptor = (ViewElementDescriptor)desc; - if (canonicalName.equals(viewDescriptor.getCanonicalClassName())) { - return viewDescriptor; - } - } - } - } - - // it's not a built-in class? Lets look if the superclass is built-in - // give up if there's no type - if (typeHierarchy == null) { - return null; - } - - IType parentType = typeHierarchy.getSuperclass(type); - if (parentType != null) { - ViewElementDescriptor parentDescriptor = getDescriptor(parentType, project, - typeHierarchy); - - if (parentDescriptor != null) { - // parent class is a valid View class with a descriptor, so we create one - // for this class. - ViewElementDescriptor descriptor = new ViewElementDescriptor(canonicalName, - canonicalName, // ui_name - canonicalName, // canonical name - null, // tooltip - null, // sdk_url - getAttributeDescriptor(type, parentDescriptor), - null, // layout attributes - null, // children - false /* mandatory */); - - // add it to the map - synchronized (mCustomDescriptorMap) { - HashMap<String, ElementDescriptor> map = mCustomDescriptorMap.get(project); - - if (map == null) { - map = new HashMap<String, ElementDescriptor>(); - mCustomDescriptorMap.put(project, map); - } - - map.put(canonicalName, descriptor); - - } - - //TODO setup listener on this resource change. - - return descriptor; - } - } - - // class is neither a built-in view class, nor extend one. return null. - return null; - } - - /** - * Returns the array of {@link AttributeDescriptor} for the specified {@link IType}. - * <p/> - * The array should contain the descriptor for this type and all its supertypes. - * @param type the type for which the {@link AttributeDescriptor} are returned. - * @param parentDescriptor the {@link ElementDescriptor} of the direct superclass. - */ - private AttributeDescriptor[] getAttributeDescriptor(IType type, - ElementDescriptor parentDescriptor) { - // TODO add the class attribute descriptors to the parent descriptors. - return parentDescriptor.getAttributes(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java deleted file mode 100644 index 7caa50f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.ViewClassInfo; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo; -import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; -import com.android.sdklib.SdkConstants; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - - -/** - * Complete description of the layout structure. - */ -public final class LayoutDescriptors implements IDescriptorProvider { - - // Public attributes names, attributes descriptors and elements descriptors - public static final String ID_ATTR = "id"; //$NON-NLS-1$ - - /** The document descriptor. Contains all layouts and views linked together. */ - private DocumentDescriptor mDescriptor = - new DocumentDescriptor("layout_doc", null); //$NON-NLS-1$ - - /** The list of all known ViewLayout descriptors. */ - private ArrayList<ElementDescriptor> mLayoutDescriptors = new ArrayList<ElementDescriptor>(); - - /** Read-Only list of View Descriptors. */ - private List<ElementDescriptor> mROLayoutDescriptors; - - /** The list of all known View (not ViewLayout) descriptors. */ - private ArrayList<ElementDescriptor> mViewDescriptors = new ArrayList<ElementDescriptor>(); - - /** Read-Only list of View Descriptors. */ - private List<ElementDescriptor> mROViewDescriptors; - - /** @return the document descriptor. Contains all layouts and views linked together. */ - public DocumentDescriptor getDescriptor() { - return mDescriptor; - } - - /** @return The read-only list of all known ViewLayout descriptors. */ - public List<ElementDescriptor> getLayoutDescriptors() { - return mROLayoutDescriptors; - } - - /** @return The read-only list of all known View (not ViewLayout) descriptors. */ - public List<ElementDescriptor> getViewDescriptors() { - return mROViewDescriptors; - } - - public ElementDescriptor[] getRootElementDescriptors() { - return mDescriptor.getChildren(); - } - - /** - * Updates the document descriptor. - * <p/> - * It first computes the new children of the descriptor and then update them - * all at once. - * <p/> - * TODO: differentiate groups from views in the tree UI? => rely on icons - * <p/> - * - * @param views The list of views in the framework. - * @param layouts The list of layouts in the framework. - */ - public synchronized void updateDescriptors(ViewClassInfo[] views, ViewClassInfo[] layouts) { - ArrayList<ElementDescriptor> newViews = new ArrayList<ElementDescriptor>(); - if (views != null) { - for (ViewClassInfo info : views) { - ElementDescriptor desc = convertView(info); - newViews.add(desc); - } - } - - ArrayList<ElementDescriptor> newLayouts = new ArrayList<ElementDescriptor>(); - if (layouts != null) { - for (ViewClassInfo info : layouts) { - ElementDescriptor desc = convertView(info); - newLayouts.add(desc); - } - } - - ArrayList<ElementDescriptor> newDescriptors = new ArrayList<ElementDescriptor>(); - newDescriptors.addAll(newLayouts); - newDescriptors.addAll(newViews); - ElementDescriptor[] newArray = newDescriptors.toArray( - new ElementDescriptor[newDescriptors.size()]); - - // Link all layouts to everything else here.. recursively - for (ElementDescriptor layoutDesc : newLayouts) { - layoutDesc.setChildren(newArray); - } - - mViewDescriptors = newViews; - mLayoutDescriptors = newLayouts; - mDescriptor.setChildren(newArray); - - mROLayoutDescriptors = Collections.unmodifiableList(mLayoutDescriptors); - mROViewDescriptors = Collections.unmodifiableList(mViewDescriptors); - } - - /** - * Creates an element descriptor from a given {@link ViewClassInfo}. - */ - private ElementDescriptor convertView(ViewClassInfo info) { - String xml_name = info.getShortClassName(); - String tooltip = info.getJavaDoc(); - - // Process all View attributes - ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>(); - DescriptorsUtils.appendAttributes(attributes, - null, // elementName - SdkConstants.NS_RESOURCES, - info.getAttributes(), - null, // requiredAttributes - null /* overrides */); - - for (ViewClassInfo link = info.getSuperClass(); - link != null; - link = link.getSuperClass()) { - AttributeInfo[] attrList = link.getAttributes(); - if (attrList.length > 0) { - attributes.add(new SeparatorAttributeDescriptor( - String.format("Attributes from %1$s", link.getShortClassName()))); - DescriptorsUtils.appendAttributes(attributes, - null, // elementName - SdkConstants.NS_RESOURCES, - attrList, - null, // requiredAttributes - null /* overrides */); - } - } - - // Process all LayoutParams attributes - ArrayList<AttributeDescriptor> layoutAttributes = new ArrayList<AttributeDescriptor>(); - LayoutParamsInfo layoutParams = info.getLayoutData(); - - for(; layoutParams != null; layoutParams = layoutParams.getSuperClass()) { - boolean need_separator = true; - for (AttributeInfo attr_info : layoutParams.getAttributes()) { - if (DescriptorsUtils.containsAttribute(layoutAttributes, - SdkConstants.NS_RESOURCES, attr_info)) { - continue; - } - if (need_separator) { - String title; - if (layoutParams.getShortClassName().equals( - AndroidConstants.CLASS_LAYOUTPARAMS)) { - title = String.format("Layout Attributes from %1$s", - layoutParams.getViewLayoutClass().getShortClassName()); - } else { - title = String.format("Layout Attributes from %1$s (%2$s)", - layoutParams.getViewLayoutClass().getShortClassName(), - layoutParams.getShortClassName()); - } - layoutAttributes.add(new SeparatorAttributeDescriptor(title)); - need_separator = false; - } - DescriptorsUtils.appendAttribute(layoutAttributes, - null, // elementName - SdkConstants.NS_RESOURCES, - attr_info, - false, // required - null /* overrides */); - } - } - - return new ViewElementDescriptor(xml_name, - xml_name, // ui_name - info.getCanonicalClassName(), - tooltip, - null, // sdk_url - attributes.toArray(new AttributeDescriptor[attributes.size()]), - layoutAttributes.toArray(new AttributeDescriptor[layoutAttributes.size()]), - null, // children - false /* mandatory */); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/ViewElementDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/ViewElementDescriptor.java deleted file mode 100644 index d718ebd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/ViewElementDescriptor.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.descriptors; - -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.layout.uimodel.UiViewElementNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * {@link ViewElementDescriptor} describes the properties expected for a given XML element node - * representing a class in an XML Layout file. - * - * @see ElementDescriptor - */ -public final class ViewElementDescriptor extends ElementDescriptor { - - private String mCanonicalClassName; - - /** The list of layout attributes. Can be empty but not null. */ - private AttributeDescriptor[] mLayoutAttributes; - - - /** - * Constructs a new {@link ViewElementDescriptor} based on its XML name, UI name, - * the canonical name of the class it represents, its tooltip, its SDK url, its attributes list, - * its children list and its mandatory flag. - * - * @param xml_name The XML element node name. Case sensitive. - * @param ui_name The XML element name for the user interface, typically capitalized. - * @param canonicalClassName The canonical class name the {@link ViewElementDescriptor} is - * representing. - * @param tooltip An optional tooltip. Can be null or empty. - * @param sdk_url An optional SKD URL. Can be null or empty. - * @param attributes The list of allowed attributes. Can be null or empty. - * @param layoutAttributes The list of layout attributes. Can be null or empty. - * @param children The list of allowed children. Can be null or empty. - * @param mandatory Whether this node must always exist (even for empty models). A mandatory - * UI node is never deleted and it may lack an actual XML node attached. A non-mandatory - * UI node MUST have an XML node attached and it will cease to exist when the XML node - * ceases to exist. - */ - public ViewElementDescriptor(String xml_name, String ui_name, - String canonicalClassName, - String tooltip, String sdk_url, - AttributeDescriptor[] attributes, AttributeDescriptor[] layoutAttributes, - ElementDescriptor[] children, boolean mandatory) { - super(xml_name, ui_name, tooltip, sdk_url, attributes, children, mandatory); - mCanonicalClassName = canonicalClassName; - mLayoutAttributes = layoutAttributes != null ? layoutAttributes : new AttributeDescriptor[0]; - } - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name, the canonical - * name of the class it represents, and its children list. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param canonicalClassName The canonical class name the {@link ViewElementDescriptor} is - * representing. - * @param children The list of allowed children. Can be null or empty. - * @param mandatory Whether this node must always exist (even for empty models). A mandatory - * UI node is never deleted and it may lack an actual XML node attached. A non-mandatory - * UI node MUST have an XML node attached and it will cease to exist when the XML node - * ceases to exist. - */ - public ViewElementDescriptor(String xml_name, String canonicalClassName, - ElementDescriptor[] children, - boolean mandatory) { - super(xml_name, children, mandatory); - mCanonicalClassName = canonicalClassName; - } - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name and children list. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param canonicalClassName The canonical class name the {@link ViewElementDescriptor} is - * representing. - * @param children The list of allowed children. Can be null or empty. - */ - public ViewElementDescriptor(String xml_name, String canonicalClassName, - ElementDescriptor[] children) { - super(xml_name, children); - mCanonicalClassName = canonicalClassName; - } - - /** - * Constructs a new {@link ElementDescriptor} based on its XML name and on the canonical - * name of the class it represents. - * The UI name is build by capitalizing the XML name. - * The UI nodes will be non-mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param canonicalClassName The canonical class name the {@link ViewElementDescriptor} is - * representing. - */ - public ViewElementDescriptor(String xml_name, String canonicalClassName) { - super(xml_name); - mCanonicalClassName = canonicalClassName; - } - - /** - * Returns the canonical name of the class represented by this element descriptor. - */ - public String getCanonicalClassName() { - return mCanonicalClassName; - } - - /** Returns the list of layout attributes. Can be empty but not null. */ - public AttributeDescriptor[] getLayoutAttributes() { - return mLayoutAttributes; - } - - /** - * @return A new {@link UiViewElementNode} linked to this descriptor. - */ - @Override - public UiElementNode createUiNode() { - return new UiViewElementNode(this); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/DropFeedback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/DropFeedback.java deleted file mode 100644 index 6e79d64..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/DropFeedback.java +++ /dev/null @@ -1,761 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.layout.LayoutConstants; -import com.android.ide.eclipse.editors.layout.LayoutEditor.UiEditorActions; -import com.android.ide.eclipse.editors.layout.parts.UiLayoutEditPart.HighlightInfo; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.draw2d.geometry.Point; -import org.eclipse.draw2d.geometry.Rectangle; - -import java.util.HashMap; -import java.util.Map.Entry; - -/** - * Utility methods used when dealing with dropping EditPart on the GLE. - * <p/> - * This class uses some temporary static storage to avoid excessive allocations during - * drop operations. It is expected to only be invoked from the main UI thread with no - * concurrent access. - */ -class DropFeedback { - - private static final int TOP = 0; - private static final int LEFT = 1; - private static final int BOTTOM = 2; - private static final int RIGHT = 3; - private static final int MAX_DIR = RIGHT; - - private static final int sOppositeDirection[] = { BOTTOM, RIGHT, TOP, LEFT }; - - private static final UiElementEditPart sTempClosests[] = new UiElementEditPart[4]; - private static final int sTempMinDists[] = new int[4]; - - - /** - * Target information computed from a drop on a RelativeLayout. - * We need only one instance of this and it is sRelativeInfo. - */ - private static class RelativeInfo { - /** The two target parts 0 and 1. They can be null, meaning a border is used. - * The direction from part 0 to 1 is always to-the-right or to-the-bottom. */ - final UiElementEditPart targetParts[] = new UiElementEditPart[2]; - /** Direction from the anchor part to the drop point. */ - int direction; - /** The index of the "anchor" part, i.e. the closest one selected by the drop. - * This can be either 0 or 1. The corresponding part can be null. */ - int anchorIndex; - } - - /** The single RelativeInfo used to compute results from a drop on a RelativeLayout */ - private static final RelativeInfo sRelativeInfo = new RelativeInfo(); - /** A temporary array of 2 {@link UiElementEditPart} to avoid allocations. */ - private static final UiElementEditPart sTempTwoParts[] = new UiElementEditPart[2]; - - - private DropFeedback() { - } - - - //----- Package methods called by users of this helper class ----- - - - /** - * This method is used by {@link ElementCreateCommand#execute()} when a new item - * needs to be "dropped" in the current XML document. It creates the new item using - * the given descriptor as a child of the given parent part. - * - * @param parentPart The parent part. - * @param descriptor The descriptor for the new XML element. - * @param where The drop location (in parent coordinates) - * @param actions The helper that actually modifies the XML model. - */ - static void addElementToXml(UiElementEditPart parentPart, - ElementDescriptor descriptor, Point where, - UiEditorActions actions) { - - String layoutXmlName = getXmlLocalName(parentPart); - RelativeInfo info = null; - UiElementEditPart sibling = null; - - if (LayoutConstants.LINEAR_LAYOUT.equals(layoutXmlName)) { - sibling = findLinearTarget(parentPart, where)[1]; - - } else if (LayoutConstants.RELATIVE_LAYOUT.equals(layoutXmlName)) { - info = findRelativeTarget(parentPart, where, sRelativeInfo); - if (info != null) { - sibling = info.targetParts[info.anchorIndex]; - sibling = getNextUiSibling(sibling); - } - } - - if (actions != null) { - UiElementNode uiSibling = sibling != null ? sibling.getUiNode() : null; - UiElementNode uiParent = parentPart.getUiNode(); - UiElementNode uiNode = actions.addElement(uiParent, uiSibling, descriptor, - false /*updateLayout*/); - - if (LayoutConstants.ABSOLUTE_LAYOUT.equals(layoutXmlName)) { - adjustAbsoluteAttributes(uiNode, where); - } else if (LayoutConstants.RELATIVE_LAYOUT.equals(layoutXmlName)) { - adustRelativeAttributes(uiNode, info); - } - } - } - - /** - * This method is used by {@link UiLayoutEditPart#showDropTarget(Point)} to compute - * highlight information when a drop target is moved over a valid drop area. - * <p/> - * Since there are no "out" parameters in Java, all the information is returned - * via the {@link HighlightInfo} structure passed as parameter. - * - * @param parentPart The parent part, always a layout. - * @param highlightInfo A structure where result is stored to perform highlight. - * @param where The target drop point, in parent's coordinates - * @return The {@link HighlightInfo} structured passed as a parameter, for convenience. - */ - static HighlightInfo computeDropFeedback(UiLayoutEditPart parentPart, - HighlightInfo highlightInfo, - Point where) { - String layoutType = getXmlLocalName(parentPart); - - if (LayoutConstants.ABSOLUTE_LAYOUT.equals(layoutType)) { - highlightInfo.anchorPoint = where; - - } else if (LayoutConstants.LINEAR_LAYOUT.equals(layoutType)) { - boolean isVertical = isVertical(parentPart); - - highlightInfo.childParts = findLinearTarget(parentPart, where); - computeLinearLine(parentPart, isVertical, highlightInfo); - - } else if (LayoutConstants.RELATIVE_LAYOUT.equals(layoutType)) { - - RelativeInfo info = findRelativeTarget(parentPart, where, sRelativeInfo); - if (info != null) { - highlightInfo.childParts = sRelativeInfo.targetParts; - computeRelativeLine(parentPart, info, highlightInfo); - } - } - - return highlightInfo; - } - - - //----- Misc utilities ----- - - /** - * Returns the next UI sibling of this part, i.e. the element which is just after in - * the UI/XML order in the same parent. Returns null if there's no such part. - * <p/> - * Note: by "UI sibling" here we mean the sibling in the UiNode hierarchy. By design the - * UiNode model has the <em>exact</em> same order as the XML model. This has nothing to do - * with the "user interface" order that you see on the rendered Android layouts (e.g. for - * LinearLayout they are the same but for AbsoluteLayout or RelativeLayout the UI/XML model - * order can be vastly different from the user interface order.) - */ - private static UiElementEditPart getNextUiSibling(UiElementEditPart part) { - if (part != null) { - UiElementNode uiNode = part.getUiNode(); - if (uiNode != null) { - uiNode = uiNode.getUiNextSibling(); - } - if (uiNode != null) { - for (Object childPart : part.getParent().getChildren()) { - if (childPart instanceof UiElementEditPart && - ((UiElementEditPart) childPart).getUiNode() == uiNode) { - return (UiElementEditPart) childPart; - } - } - } - } - return null; - } - - /** - * Returns the XML local name of the ui node associated with this edit part or null. - */ - private static String getXmlLocalName(UiElementEditPart editPart) { - UiElementNode uiNode = editPart.getUiNode(); - if (uiNode != null) { - ElementDescriptor desc = uiNode.getDescriptor(); - if (desc != null) { - return desc.getXmlLocalName(); - } - } - return null; - } - - /** - * Adjusts the attributes of a new node dropped in an AbsoluteLayout. - * - * @param uiNode The new node being dropped. - * @param where The drop location (in parent coordinates) - */ - private static void adjustAbsoluteAttributes(final UiElementNode uiNode, final Point where) { - if (where == null) { - return; - } - uiNode.getEditor().editXmlModel(new Runnable() { - public void run() { - uiNode.setAttributeValue(LayoutConstants.ATTR_LAYOUT_X, - String.format(LayoutConstants.VALUE_N_DIP, where.x), - false /* override */); - uiNode.setAttributeValue(LayoutConstants.ATTR_LAYOUT_Y, - String.format(LayoutConstants.VALUE_N_DIP, where.y), - false /* override */); - - uiNode.commitDirtyAttributesToXml(); - } - }); - } - - /** - * Adjusts the attributes of a new node dropped in a RelativeLayout: - * <ul> - * <li> anchor part: the one the user selected (or the closest) and to which the new one - * will "attach". The anchor part can be null, either because the layout is currently - * empty or the user is attaching to an existing empty border. - * <li> direction: the direction from the anchor part to the drop point. That's also the - * direction from the anchor part to the new part. - * <li> the new node; it is created either after the anchor for right or top directions - * or before the anchor for left or bottom directions. This means the new part can - * reference the id of the anchor part. - * </ul> - * - * Several cases: - * <ul> - * <li> set: layout_above/below/toLeftOf/toRightOf to point to the anchor. - * <li> copy: layout_centerHorizontal for top/bottom directions - * <li> copy: layout_centerVertical for left/right directions. - * <li> copy: layout_above/below/toLeftOf/toRightOf for the orthogonal direction - * (i.e. top/bottom or left/right.) - * </ul> - * - * @param uiNode The new node being dropped. - * @param info The context computed by {@link #findRelativeTarget(UiElementEditPart, Point, RelativeInfo)}. - */ - private static void adustRelativeAttributes(final UiElementNode uiNode, RelativeInfo info) { - if (uiNode == null || info == null) { - return; - } - - final UiElementEditPart anchorPart = info.targetParts[info.anchorIndex]; // can be null - final int direction = info.direction; - - uiNode.getEditor().editXmlModel(new Runnable() { - public void run() { - HashMap<String, String> map = new HashMap<String, String>(); - - UiElementNode anchorUiNode = anchorPart != null ? anchorPart.getUiNode() : null; - String anchorId = anchorUiNode != null - ? anchorUiNode.getAttributeValue("id") //$NON-NLS-1$ - : null; - - if (anchorId == null) { - anchorId = DescriptorsUtils.getFreeWidgetId(anchorUiNode); - anchorUiNode.setAttributeValue("id", anchorId, true /*override*/); //$NON-NLS-1$ - } - - if (anchorId != null) { - switch(direction) { - case TOP: - map.put(LayoutConstants.ATTR_LAYOUT_ABOVE, anchorId); - break; - case BOTTOM: - map.put(LayoutConstants.ATTR_LAYOUT_BELOW, anchorId); - break; - case LEFT: - map.put(LayoutConstants.ATTR_LAYOUT_TO_LEFT_OF, anchorId); - break; - case RIGHT: - map.put(LayoutConstants.ATTR_LAYOUT_TO_RIGHT_OF, anchorId); - break; - } - - switch(direction) { - case TOP: - case BOTTOM: - map.put(LayoutConstants.ATTR_LAYOUT_CENTER_HORIZONTAL, - anchorUiNode.getAttributeValue( - LayoutConstants.ATTR_LAYOUT_CENTER_HORIZONTAL)); - - map.put(LayoutConstants.ATTR_LAYOUT_TO_LEFT_OF, - anchorUiNode.getAttributeValue( - LayoutConstants.ATTR_LAYOUT_TO_LEFT_OF)); - map.put(LayoutConstants.ATTR_LAYOUT_TO_RIGHT_OF, - anchorUiNode.getAttributeValue( - LayoutConstants.ATTR_LAYOUT_TO_RIGHT_OF)); - break; - case LEFT: - case RIGHT: - map.put(LayoutConstants.ATTR_LAYOUT_CENTER_VERTICAL, - anchorUiNode.getAttributeValue( - LayoutConstants.ATTR_LAYOUT_CENTER_VERTICAL)); - map.put(LayoutConstants.ATTR_LAYOUT_ALIGN_BASELINE, - anchorUiNode.getAttributeValue( - LayoutConstants.ATTR_LAYOUT_ALIGN_BASELINE)); - - map.put(LayoutConstants.ATTR_LAYOUT_ABOVE, - anchorUiNode.getAttributeValue(LayoutConstants.ATTR_LAYOUT_ABOVE)); - map.put(LayoutConstants.ATTR_LAYOUT_BELOW, - anchorUiNode.getAttributeValue(LayoutConstants.ATTR_LAYOUT_BELOW)); - break; - } - } else { - // We don't have an anchor node. Assume we're targeting a border and align - // to the parent. - switch(direction) { - case TOP: - map.put(LayoutConstants.ATTR_LAYOUT_ALIGN_PARENT_TOP, - LayoutConstants.VALUE_TRUE); - break; - case BOTTOM: - map.put(LayoutConstants.ATTR_LAYOUT_ALIGN_PARENT_BOTTOM, - LayoutConstants.VALUE_TRUE); - break; - case LEFT: - map.put(LayoutConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT, - LayoutConstants.VALUE_TRUE); - break; - case RIGHT: - map.put(LayoutConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT, - LayoutConstants.VALUE_TRUE); - break; - } - } - - for (Entry<String, String> entry : map.entrySet()) { - uiNode.setAttributeValue(entry.getKey(), entry.getValue(), true /* override */); - } - uiNode.commitDirtyAttributesToXml(); - } - }); - } - - - //----- LinearLayout -------- - - /** - * For a given parent edit part that MUST represent a LinearLayout, finds the - * element before which the location points. - * <p/> - * This computes the edit part that corresponds to what will be the "next sibling" of the new - * element. - * <p/> - * It returns null if it can't be determined, in which case the element will be added at the - * end of the parent child list. - * - * @return The edit parts that correspond to what will be the "prev" and "next sibling" of the - * new element. The previous sibling can be null if adding before the first element. - * The next sibling can be null if adding after the last element. - */ - private static UiElementEditPart[] findLinearTarget(UiElementEditPart parent, Point point) { - // default orientation is horizontal - boolean isVertical = isVertical(parent); - - int target = isVertical ? point.y : point.x; - - UiElementEditPart prev = null; - UiElementEditPart next = null; - - for (Object child : parent.getChildren()) { - if (child instanceof UiElementEditPart) { - UiElementEditPart childPart = (UiElementEditPart) child; - Point p = childPart.getBounds().getCenter(); - int middle = isVertical ? p.y : p.x; - if (target < middle) { - next = childPart; - break; - } - prev = childPart; - } - } - - sTempTwoParts[0] = prev; - sTempTwoParts[1] = next; - return sTempTwoParts; - } - - /** - * Computes the highlight line between two parts. - * <p/> - * The two parts are listed in HighlightInfo.childParts[2]. Any of the parts - * can be null. - * The result is stored in HighlightInfo. - * <p/> - * Caller must clear the HighlightInfo as appropriate before this call. - * - * @param parentPart The parent part, always a layout. - * @param isVertical True for vertical parts, thus computing an horizontal line. - * @param highlightInfo The in-out highlight info. - */ - private static void computeLinearLine(UiLayoutEditPart parentPart, - boolean isVertical, HighlightInfo highlightInfo) { - Rectangle r = parentPart.getBounds(); - - if (isVertical) { - Point p = null; - UiElementEditPart part = highlightInfo.childParts[0]; - if (part != null) { - p = part.getBounds().getBottom(); - } else { - part = highlightInfo.childParts[1]; - if (part != null) { - p = part.getBounds().getTop(); - } - } - if (p != null) { - // horizontal line with middle anchor point - highlightInfo.tempPoints[0].setLocation(0, p.y); - highlightInfo.tempPoints[1].setLocation(r.width, p.y); - highlightInfo.linePoints = highlightInfo.tempPoints; - highlightInfo.anchorPoint = p.setLocation(r.width / 2, p.y); - } - } else { - Point p = null; - UiElementEditPart part = highlightInfo.childParts[0]; - if (part != null) { - p = part.getBounds().getRight(); - } else { - part = highlightInfo.childParts[1]; - if (part != null) { - p = part.getBounds().getLeft(); - } - } - if (p != null) { - // vertical line with middle anchor point - highlightInfo.tempPoints[0].setLocation(p.x, 0); - highlightInfo.tempPoints[1].setLocation(p.x, r.height); - highlightInfo.linePoints = highlightInfo.tempPoints; - highlightInfo.anchorPoint = p.setLocation(p.x, r.height / 2); - } - } - } - - /** - * Returns true if the linear layout is marked as vertical. - * - * @param parent The a layout part that must be a LinearLayout - * @return True if the linear layout has a vertical orientation attribute. - */ - private static boolean isVertical(UiElementEditPart parent) { - String orientation = parent.getStringAttr("orientation"); //$NON-NLS-1$ - boolean isVertical = "vertical".equals(orientation) || //$NON-NLS-1$ - "1".equals(orientation); //$NON-NLS-1$ - return isVertical; - } - - - //----- RelativeLayout -------- - - /** - * Finds the "target" relative layout item for the drop operation & feedback. - * <p/> - * If the drop point is exactly on a current item, simply returns the side the drop will occur - * compared to the center of that element. For the actual XML, we'll need to insert *after* - * that element to make sure that referenced are defined in the right order. - * In that case the result contains two elements, the second one always being on the right or - * bottom side of the first one. When insert in XML, we want to insert right before that - * second element or at the end of the child list if the second element is null. - * <p/> - * If the drop point is not exactly on a current element, find the closest in each - * direction and align with the two closest of these. - * - * @return null if we fail to find anything (such as there are currently no items to compare - * with); otherwise fills the {@link RelativeInfo} and return it. - */ - private static RelativeInfo findRelativeTarget(UiElementEditPart parent, - Point point, - RelativeInfo outInfo) { - - for (int i = 0; i < 4; i++) { - sTempMinDists[i] = Integer.MAX_VALUE; - sTempClosests[i] = null; - } - - - for (Object child : parent.getChildren()) { - if (child instanceof UiElementEditPart) { - UiElementEditPart childPart = (UiElementEditPart) child; - Rectangle r = childPart.getBounds(); - if (r.contains(point)) { - - float rx = ((float)(point.x - r.x) / (float)r.width ) - 0.5f; - float ry = ((float)(point.y - r.y) / (float)r.height) - 0.5f; - - /* TOP - * \ / - * \ / - * L X R - * / \ - * / \ - * BOT - */ - - int index = 0; - if (Math.abs(rx) >= Math.abs(ry)) { - if (rx < 0) { - outInfo.direction = LEFT; - index = 1; - } else { - outInfo.direction = RIGHT; - } - } else { - if (ry < 0) { - outInfo.direction = TOP; - index = 1; - } else { - outInfo.direction = BOTTOM; - } - } - - outInfo.anchorIndex = index; - outInfo.targetParts[index] = childPart; - outInfo.targetParts[1 - index] = findClosestPart(childPart, - outInfo.direction); - - return outInfo; - } - - computeClosest(point, childPart, sTempClosests, sTempMinDists, TOP); - computeClosest(point, childPart, sTempClosests, sTempMinDists, LEFT); - computeClosest(point, childPart, sTempClosests, sTempMinDists, BOTTOM); - computeClosest(point, childPart, sTempClosests, sTempMinDists, RIGHT); - } - } - - UiElementEditPart closest = null; - int minDist = Integer.MAX_VALUE; - int minDir = -1; - - for (int i = 0; i <= MAX_DIR; i++) { - if (sTempClosests[i] != null && sTempMinDists[i] < minDist) { - closest = sTempClosests[i]; - minDist = sTempMinDists[i]; - minDir = i; - } - } - - if (closest != null) { - int index = 0; - switch(minDir) { - case TOP: - case LEFT: - index = 0; - break; - case BOTTOM: - case RIGHT: - index = 1; - break; - } - outInfo.anchorIndex = index; - outInfo.targetParts[index] = closest; - outInfo.targetParts[1 - index] = findClosestPart(closest, sOppositeDirection[minDir]); - outInfo.direction = sOppositeDirection[minDir]; - return outInfo; - } - - return null; - } - - /** - * Computes the highlight line for a drop on a RelativeLayout. - * <p/> - * The line is always placed on the side of the anchor part indicated by the - * direction. The direction always point from the anchor part to the drop point. - * <p/> - * If there's no anchor part, use the other one with a reversed direction. - * <p/> - * On output, this updates the {@link HighlightInfo}. - */ - private static void computeRelativeLine(UiLayoutEditPart parentPart, - RelativeInfo relInfo, - HighlightInfo highlightInfo) { - - UiElementEditPart[] parts = relInfo.targetParts; - int dir = relInfo.direction; - int index = relInfo.anchorIndex; - UiElementEditPart part = parts[index]; - - if (part == null) { - dir = sOppositeDirection[dir]; - part = parts[1 - index]; - } - if (part == null) { - // give up if both parts are null - return; - } - - Rectangle r = part.getBounds(); - Point p = null; - switch(dir) { - case TOP: - p = r.getTop(); - break; - case BOTTOM: - p = r.getBottom(); - break; - case LEFT: - p = r.getLeft(); - break; - case RIGHT: - p = r.getRight(); - break; - } - - highlightInfo.anchorPoint = p; - - r = parentPart.getBounds(); - switch(dir) { - case TOP: - case BOTTOM: - // horizontal line with middle anchor point - highlightInfo.tempPoints[0].setLocation(0, p.y); - highlightInfo.tempPoints[1].setLocation(r.width, p.y); - highlightInfo.linePoints = highlightInfo.tempPoints; - highlightInfo.anchorPoint = p; - break; - case LEFT: - case RIGHT: - // vertical line with middle anchor point - highlightInfo.tempPoints[0].setLocation(p.x, 0); - highlightInfo.tempPoints[1].setLocation(p.x, r.height); - highlightInfo.linePoints = highlightInfo.tempPoints; - highlightInfo.anchorPoint = p; - break; - } - } - - /** - * Given a certain reference point (drop point), computes the distance to the given - * part in the given direction. For example if direction is top, only accepts parts which - * bottom is above the reference point, computes their distance and then updates the - * current minimal distances and current closest parts arrays accordingly. - */ - private static void computeClosest(Point refPoint, - UiElementEditPart compareToPart, - UiElementEditPart[] currClosests, - int[] currMinDists, - int direction) { - Rectangle r = compareToPart.getBounds(); - - Point p = null; - boolean usable = false; - - switch(direction) { - case TOP: - p = r.getBottom(); - usable = p.y <= refPoint.y; - break; - case BOTTOM: - p = r.getTop(); - usable = p.y >= refPoint.y; - break; - case LEFT: - p = r.getRight(); - usable = p.x <= refPoint.x; - break; - case RIGHT: - p = r.getLeft(); - usable = p.x >= refPoint.x; - break; - } - - if (usable) { - int d = p.getDistance2(refPoint); - if (d < currMinDists[direction]) { - currMinDists[direction] = d; - currClosests[direction] = compareToPart; - } - } - } - - /** - * Given a reference parts, finds the closest part in the parent in the given direction. - * For example if direction is top, finds the closest sibling part which is above the - * reference part and non-overlapping (they can touch.) - */ - private static UiElementEditPart findClosestPart(UiElementEditPart referencePart, - int direction) { - if (referencePart == null || referencePart.getParent() == null) { - return null; - } - - Rectangle r = referencePart.getBounds(); - Point ref = null; - switch(direction) { - case TOP: - ref = r.getTop(); - break; - case BOTTOM: - ref = r.getBottom(); - break; - case LEFT: - ref = r.getLeft(); - break; - case RIGHT: - ref = r.getRight(); - break; - } - - int minDist = Integer.MAX_VALUE; - UiElementEditPart closestPart = null; - - for (Object childPart : referencePart.getParent().getChildren()) { - if (childPart != referencePart && childPart instanceof UiElementEditPart) { - r = ((UiElementEditPart) childPart).getBounds(); - Point p = null; - boolean usable = false; - - switch(direction) { - case TOP: - p = r.getBottom(); - usable = p.y <= ref.y; - break; - case BOTTOM: - p = r.getTop(); - usable = p.y >= ref.y; - break; - case LEFT: - p = r.getRight(); - usable = p.x <= ref.x; - break; - case RIGHT: - p = r.getLeft(); - usable = p.x >= ref.x; - break; - } - - if (usable) { - int d = p.getDistance2(ref); - if (d < minDist) { - minDist = d; - closestPart = (UiElementEditPart) childPart; - } - } - } - } - - return closestPart; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/ElementCreateCommand.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/ElementCreateCommand.java deleted file mode 100644 index d36d9f7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/ElementCreateCommand.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.layout.LayoutEditor; -import com.android.ide.eclipse.editors.layout.LayoutEditor.UiEditorActions; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.draw2d.geometry.Point; -import org.eclipse.gef.commands.Command; - -/** - * A command that knows how to instantiate a new element based on a given {@link ElementDescriptor}, - * the parent {@link UiElementEditPart} and an optional target location. - */ -public class ElementCreateCommand extends Command { - - /** Descriptor of the new element to create */ - private final ElementDescriptor mDescriptor; - /** The edit part that hosts the new edit part */ - private final UiElementEditPart mParentPart; - /** The drop location in parent coordinates */ - private final Point mTargetPoint; - - /** - * Creates a new {@link ElementCreateCommand}. - * - * @param descriptor Descriptor of the new element to create - * @param targetPart The edit part that hosts the new edit part - * @param targetPoint The drop location in parent coordinates - */ - public ElementCreateCommand(ElementDescriptor descriptor, - UiElementEditPart targetPart, Point targetPoint) { - mDescriptor = descriptor; - mParentPart = targetPart; - mTargetPoint = targetPoint; - } - - // --- Methods inherited from Command --- - - @Override - public boolean canExecute() { - return mDescriptor != null && - mParentPart != null && - mParentPart.getUiNode() != null && - mParentPart.getUiNode().getEditor() instanceof LayoutEditor; - } - - @Override - public void execute() { - super.execute(); - UiElementNode uiParent = mParentPart.getUiNode(); - if (uiParent != null) { - final AndroidEditor editor = uiParent.getEditor(); - if (editor instanceof LayoutEditor) { - ((LayoutEditor) editor).wrapUndoRecording( - String.format("Create %1$s", mDescriptor.getXmlLocalName()), - new Runnable() { - public void run() { - UiEditorActions actions = ((LayoutEditor) editor).getUiEditorActions(); - if (actions != null) { - DropFeedback.addElementToXml(mParentPart, mDescriptor, mTargetPoint, - actions); - } - } - }); - } - } - } - - @Override - public void redo() { - throw new UnsupportedOperationException("redo not supported by this command"); //$NON-NLS-1$ - } - - @Override - public void undo() { - throw new UnsupportedOperationException("undo not supported by this command"); //$NON-NLS-1$ - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/ElementFigure.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/ElementFigure.java deleted file mode 100644 index f863037..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/ElementFigure.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import org.eclipse.draw2d.ColorConstants; -import org.eclipse.draw2d.Figure; -import org.eclipse.draw2d.Graphics; -import org.eclipse.draw2d.geometry.Rectangle; -import org.eclipse.swt.SWT; - - -/** - * The figure used to draw basic elements. - * <p/> - * The figure is totally empty and transparent except for the selection border. - */ -class ElementFigure extends Figure { - - private boolean mIsSelected; - private Rectangle mInnerBounds; - - public ElementFigure() { - setOpaque(false); - } - - public void setSelected(boolean isSelected) { - if (isSelected != mIsSelected) { - mIsSelected = isSelected; - repaint(); - } - } - - @Override - public void setBounds(Rectangle rect) { - super.setBounds(rect); - - mInnerBounds = getBounds().getCopy(); - if (mInnerBounds.width > 0) { - mInnerBounds.width--; - } - if (mInnerBounds.height > 0) { - mInnerBounds.height--; - } - } - - public Rectangle getInnerBounds() { - return mInnerBounds; - } - - @Override - protected void paintBorder(Graphics graphics) { - super.paintBorder(graphics); - - if (mIsSelected) { - graphics.setLineWidth(1); - graphics.setLineStyle(SWT.LINE_SOLID); - graphics.setForegroundColor(ColorConstants.red); - graphics.drawRectangle(getInnerBounds()); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/LayoutFigure.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/LayoutFigure.java deleted file mode 100644 index 55ed39b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/LayoutFigure.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.layout.parts.UiLayoutEditPart.HighlightInfo; - -import org.eclipse.draw2d.ColorConstants; -import org.eclipse.draw2d.Figure; -import org.eclipse.draw2d.Graphics; -import org.eclipse.draw2d.geometry.Rectangle; -import org.eclipse.swt.SWT; - -/** - * The figure used to draw the feedback on a layout. - * <p/> - * By default the figure is transparent and empty. - * The base {@link ElementFigure} knows how to draw the selection border. - * This figure knows how to draw the drop feedback. - */ -class LayoutFigure extends ElementFigure { - - private HighlightInfo mHighlightInfo; - - public LayoutFigure() { - super(); - } - - public void setHighlighInfo(HighlightInfo highlightInfo) { - mHighlightInfo = highlightInfo; - repaint(); - } - - /** - * Paints the "border" for this figure. - * <p/> - * The parent {@link Figure#paint(Graphics)} calls {@link #paintFigure(Graphics)} then - * {@link #paintClientArea(Graphics)} then {@link #paintBorder(Graphics)}. Here we thus - * draw the actual highlight border but also the highlight anchor lines and points so that - * we can make sure they are all drawn on top of the border. - * <p/> - * Note: This method doesn't really need to restore its graphic state. The parent - * Figure will do it for us. - * <p/> - * - * @param graphics The Graphics object used for painting - */ - @Override - protected void paintBorder(Graphics graphics) { - super.paintBorder(graphics); - - if (mHighlightInfo == null) { - return; - } - - // Draw the border. We want other highlighting to be drawn on top of the border. - if (mHighlightInfo.drawDropBorder) { - graphics.setLineWidth(3); - graphics.setLineStyle(SWT.LINE_SOLID); - graphics.setForegroundColor(ColorConstants.green); - graphics.drawRectangle(getInnerBounds().getCopy().shrink(1, 1)); - } - - Rectangle bounds = getBounds(); - int bx = bounds.x; - int by = bounds.y; - int w = bounds.width; - int h = bounds.height; - - // Draw frames of target child parts, if any - if (mHighlightInfo.childParts != null) { - graphics.setLineWidth(2); - graphics.setLineStyle(SWT.LINE_DOT); - graphics.setForegroundColor(ColorConstants.lightBlue); - for (UiElementEditPart part : mHighlightInfo.childParts) { - if (part != null) { - graphics.drawRectangle(part.getBounds().getCopy().translate(bx, by)); - } - } - } - - // Draw the target line, if any - if (mHighlightInfo.linePoints != null) { - int x1 = mHighlightInfo.linePoints[0].x; - int y1 = mHighlightInfo.linePoints[0].y; - int x2 = mHighlightInfo.linePoints[1].x; - int y2 = mHighlightInfo.linePoints[1].y; - - // if the line is right to the edge, draw it one pixel more inside so that the - // full 2-pixel width be visible. - if (x1 <= 0) x1++; - if (x2 <= 0) x2++; - if (y1 <= 0) y1++; - if (y2 <= 0) y2++; - - if (x1 >= w - 1) x1--; - if (x2 >= w - 1) x2--; - if (y1 >= h - 1) y1--; - if (y2 >= h - 1) y2--; - - x1 += bx; - x2 += bx; - y1 += by; - y2 += by; - - graphics.setLineWidth(2); - graphics.setLineStyle(SWT.LINE_DASH); - graphics.setLineCap(SWT.CAP_ROUND); - graphics.setForegroundColor(ColorConstants.orange); - graphics.drawLine(x1, y1, x2, y2); - } - - // Draw the anchor point, if any - if (mHighlightInfo.anchorPoint != null) { - int x = mHighlightInfo.anchorPoint.x; - int y = mHighlightInfo.anchorPoint.y; - - // If the point is right on the edge, draw it one pixel inside so that it - // matches the highlight line. It makes it slightly more visible that way. - if (x <= 0) x++; - if (y <= 0) y++; - if (x >= w - 1) x--; - if (y >= h - 1) y--; - x += bx; - y += by; - - graphics.setLineWidth(2); - graphics.setLineStyle(SWT.LINE_SOLID); - graphics.setLineCap(SWT.CAP_ROUND); - graphics.setForegroundColor(ColorConstants.orange); - graphics.drawLine(x-5, y-5, x+5, y+5); - graphics.drawLine(x-5, y+5, x+5, y-5); - // 7 * cos(45) == 5 so we use 8 for the circle radius (it looks slightly better than 7) - graphics.setLineWidth(1); - graphics.drawOval(x-8, y-8, 16, 16); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiDocumentEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiDocumentEditPart.java deleted file mode 100644 index 2f7636d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiDocumentEditPart.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.draw2d.AbstractBackground; -import org.eclipse.draw2d.ColorConstants; -import org.eclipse.draw2d.FreeformLayer; -import org.eclipse.draw2d.FreeformLayout; -import org.eclipse.draw2d.Graphics; -import org.eclipse.draw2d.IFigure; -import org.eclipse.draw2d.Label; -import org.eclipse.draw2d.geometry.Insets; -import org.eclipse.draw2d.geometry.Point; -import org.eclipse.draw2d.geometry.Rectangle; -import org.eclipse.gef.EditPart; -import org.eclipse.gef.EditPolicy; -import org.eclipse.gef.Request; -import org.eclipse.gef.RequestConstants; -import org.eclipse.gef.editpolicies.RootComponentEditPolicy; -import org.eclipse.gef.requests.DropRequest; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.PaletteData; -import org.eclipse.swt.widgets.Display; - -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; - -/** - * Graphical edit part for the root document. - * <p/> - * It acts as a simple container. - */ -public class UiDocumentEditPart extends UiElementEditPart { - - private Display mDisplay; - private FreeformLayer mLayer; - private ImageBackground mImage; - private Label mChild = null; - - final static class ImageBackground extends AbstractBackground { - - private BufferedImage mBufferedImage; - private Image mImage; - - ImageBackground() { - } - - ImageBackground(BufferedImage image, Display display) { - setImage(image, display); - } - - @Override - public void paintBackground(IFigure figure, Graphics graphics, Insets insets) { - if (mImage != null) { - Rectangle rect = getPaintRectangle(figure, insets); - graphics.drawImage(mImage, rect.x, rect.y); - } - } - - void setImage(BufferedImage image, Display display) { - if (image != null) { - int[] data = ((DataBufferInt)image.getData().getDataBuffer()).getData(); - - ImageData imageData = new ImageData(image.getWidth(), image.getHeight(), 32, - new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); - - imageData.setPixels(0, 0, data.length, data, 0); - - mImage = new Image(display, imageData); - } else { - mImage = null; - } - } - - BufferedImage getBufferedImage() { - return mBufferedImage; - } - } - - public UiDocumentEditPart(UiDocumentNode uiDocumentNode, Display display) { - super(uiDocumentNode); - mDisplay = display; - } - - @Override - protected IFigure createFigure() { - mLayer = new FreeformLayer(); - mLayer.setLayoutManager(new FreeformLayout()); - - mLayer.setOpaque(true); - mLayer.setBackgroundColor(ColorConstants.lightGray); - - return mLayer; - } - - @Override - protected void refreshVisuals() { - UiElementNode model = (UiElementNode)getModel(); - - Object editData = model.getEditData(); - if (editData instanceof BufferedImage) { - BufferedImage image = (BufferedImage)editData; - - if (mImage == null || image != mImage.getBufferedImage()) { - mImage = new ImageBackground(image, mDisplay); - } - - mLayer.setBorder(mImage); - - if (mChild != null && mChild.getParent() == mLayer) { - mLayer.remove(mChild); - } - } else if (editData instanceof String) { - mLayer.setBorder(null); - if (mChild == null) { - mChild = new Label(); - } - mChild.setText((String)editData); - - if (mChild != null && mChild.getParent() != mLayer) { - mLayer.add(mChild); - } - Rectangle bounds = mChild.getTextBounds(); - bounds.x = bounds.y = 0; - mLayer.setConstraint(mChild, bounds); - } - - // refresh the children as well - refreshChildrenVisuals(); - } - - @Override - protected void hideSelection() { - // no selection at this level. - } - - @Override - protected void showSelection() { - // no selection at this level. - } - - @Override - protected void createEditPolicies() { - super.createEditPolicies(); - - // This policy indicates this a root component that cannot be removed - installEditPolicy(EditPolicy.COMPONENT_ROLE, new RootComponentEditPolicy()); - - installLayoutEditPolicy(this); - } - - /** - * Returns the EditPart that should be used as the target for the specified Request. - * For instance this is called during drag'n'drop with a CreateRequest. - * <p/> - * For the root document, we want the first child edit part to the be the target - * since an XML document can have only one root element. - * - * {@inheritDoc} - */ - @Override - public EditPart getTargetEditPart(Request request) { - if (request != null && request.getType() == RequestConstants.REQ_CREATE) { - // We refuse the drop if it's not in the bounds of the document. - if (request instanceof DropRequest) { - Point where = ((DropRequest) request).getLocation().getCopy(); - UiElementNode uiNode = getUiNode(); - if (uiNode instanceof UiDocumentNode) { - // Take the bounds of the background image as the valid drop zone - Object editData = uiNode.getEditData(); - if (editData instanceof BufferedImage) { - BufferedImage image = (BufferedImage)editData; - int w = image.getWidth(); - int h = image.getHeight(); - if (where.x > w || where.y > h) { - return null; - } - } - - } - } - - // For the root document, we want the first child edit part to the be the target - // since an XML document can have only one root element. - if (getChildren().size() > 0) { - Object o = getChildren().get(0); - if (o instanceof EditPart) { - return ((EditPart) o).getTargetEditPart(request); - } - } - } - return super.getTargetEditPart(request); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiDocumentTreeEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiDocumentTreeEditPart.java deleted file mode 100644 index af22afb..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiDocumentTreeEditPart.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; - -import java.util.List; - -/** - * Implementation of {@link UiElementTreeEditPart} for the document root. - */ -public class UiDocumentTreeEditPart extends UiElementTreeEditPart { - - public UiDocumentTreeEditPart(UiDocumentNode model) { - super(model); - } - - @SuppressWarnings("unchecked") - @Override - protected List getModelChildren() { - return getUiNode().getUiChildren(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java deleted file mode 100644 index a2e05c7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementEditPart.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.SdkConstants; - -import org.eclipse.draw2d.IFigure; -import org.eclipse.draw2d.geometry.Point; -import org.eclipse.draw2d.geometry.Rectangle; -import org.eclipse.gef.DragTracker; -import org.eclipse.gef.EditPart; -import org.eclipse.gef.EditPolicy; -import org.eclipse.gef.GraphicalEditPart; -import org.eclipse.gef.Request; -import org.eclipse.gef.RequestConstants; -import org.eclipse.gef.commands.Command; -import org.eclipse.gef.editparts.AbstractGraphicalEditPart; -import org.eclipse.gef.editpolicies.LayoutEditPolicy; -import org.eclipse.gef.editpolicies.SelectionEditPolicy; -import org.eclipse.gef.requests.CreateRequest; -import org.eclipse.gef.requests.DropRequest; -import org.eclipse.gef.tools.SelectEditPartTracker; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - -import java.util.List; - -/** - * An {@link EditPart} for a {@link UiElementNode}. - */ -public abstract class UiElementEditPart extends AbstractGraphicalEditPart - implements IUiUpdateListener { - - public UiElementEditPart(UiElementNode uiElementNode) { - setModel(uiElementNode); - } - - //------------------------- - // Derived classes must define these - - abstract protected void hideSelection(); - abstract protected void showSelection(); - - //------------------------- - // Base class overrides - - @Override - public DragTracker getDragTracker(Request request) { - return new SelectEditPartTracker(this); - } - - @Override - protected void createEditPolicies() { - /* - * This is no longer needed, as a selection edit policy is set by the parent layout. - * Leave this code commented out right now, I'll want to play with this later. - * - installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, - new NonResizableSelectionEditPolicy(this)); - */ - } - - /* (non-javadoc) - * Returns a List containing the children model objects. - * Must not return null, instead use the super which returns an empty list. - */ - @SuppressWarnings("unchecked") - @Override - protected List getModelChildren() { - return getUiNode().getUiChildren(); - } - - @Override - public void activate() { - super.activate(); - getUiNode().addUpdateListener(this); - } - - @Override - public void deactivate() { - super.deactivate(); - getUiNode().removeUpdateListener(this); - } - - @Override - protected void refreshVisuals() { - if (getFigure().getParent() != null) { - ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), getBounds()); - } - - // update the visuals of the children as well - refreshChildrenVisuals(); - } - - protected void refreshChildrenVisuals() { - if (children != null) { - for (Object child : children) { - if (child instanceof UiElementEditPart) { - UiElementEditPart childPart = (UiElementEditPart)child; - childPart.refreshVisuals(); - } - } - } - } - - //------------------------- - // IUiUpdateListener implementation - - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) { - // TODO: optimize by refreshing only when needed - switch(state) { - case ATTR_UPDATED: - refreshVisuals(); - break; - case CHILDREN_CHANGED: - refreshChildren(); - - // new children list, need to update the layout - refreshVisuals(); - break; - case CREATED: - refreshVisuals(); - break; - case DELETED: - // pass - break; - } - } - - //------------------------- - // Local methods - - /** @return The object model casted to an {@link UiElementNode} */ - public final UiElementNode getUiNode() { - return (UiElementNode) getModel(); - } - - protected final ElementDescriptor getDescriptor() { - return getUiNode().getDescriptor(); - } - - protected final UiElementEditPart getEditPartParent() { - EditPart parent = getParent(); - if (parent instanceof UiElementEditPart) { - return (UiElementEditPart)parent; - } - return null; - } - - /** - * Returns a given XML attribute. - * @param attrName The local name of the attribute. - * @return the attribute as a {@link String}, if it exists, or <code>null</code> - */ - protected final String getStringAttr(String attrName) { - UiElementNode uiNode = getUiNode(); - if (uiNode.getXmlNode() != null) { - Node xmlNode = uiNode.getXmlNode(); - if (xmlNode != null) { - NamedNodeMap nodeAttributes = xmlNode.getAttributes(); - if (nodeAttributes != null) { - Node attr = nodeAttributes.getNamedItemNS( - SdkConstants.NS_RESOURCES, attrName); - if (attr != null) { - return attr.getNodeValue(); - } - } - } - } - return null; - } - - protected final Rectangle getBounds() { - UiElementNode model = (UiElementNode)getModel(); - - Object editData = model.getEditData(); - - if (editData != null) { - // assert with fully qualified class name to prevent import changes to another - // Rectangle class. - assert (editData instanceof org.eclipse.draw2d.geometry.Rectangle); - - return (Rectangle)editData; - } - - // return a dummy rect - return new Rectangle(0, 0, 0, 0); - } - - /** - * Returns the EditPart that should be used as the target for the specified Request. - * <p/> - * For instance this is called during drag'n'drop with a CreateRequest. - * <p/> - * Reject being a target for elements which descriptor does not allow children. - * - * {@inheritDoc} - */ - @Override - public EditPart getTargetEditPart(Request request) { - if (request != null && request.getType() == RequestConstants.REQ_CREATE) { - // Reject being a target for elements which descriptor does not allow children. - if (!getUiNode().getDescriptor().hasChildren()) { - return null; - } - } - return super.getTargetEditPart(request); - } - - /** - * Used by derived classes {@link UiDocumentEditPart} and {@link UiLayoutEditPart} - * to accept drag'n'drop of new items from the palette. - * - * @param layoutEditPart The layout edit part where this policy is installed. It can - * be either a {@link UiDocumentEditPart} or a {@link UiLayoutEditPart}. - */ - protected void installLayoutEditPolicy(final UiElementEditPart layoutEditPart) { - // This policy indicates how elements can be constrained by the layout. - // TODO Right now we use the XY layout policy since our constraints are - // handled by the android rendering engine rather than GEF. Tweak as - // appropriate. - installEditPolicy(EditPolicy.LAYOUT_ROLE, new LayoutEditPolicy() { - - /** - * We don't allow layout children to be resized yet. - * <p/> - * Typical choices would be: - * <ul> - * <li> ResizableEditPolicy, to allow for selection, move and resize. - * <li> NonResizableEditPolicy, to allow for selection, move but not resize. - * <li> SelectionEditPolicy to allow for only selection. - * </ul> - * <p/> - * TODO: make this depend on the part layout. For an AbsoluteLayout we should - * probably use a NonResizableEditPolicy and SelectionEditPolicy for the rest. - * Whether to use ResizableEditPolicy or NonResizableEditPolicy should depend - * on the child in an AbsoluteLayout. - */ - @Override - protected EditPolicy createChildEditPolicy(EditPart child) { - if (child instanceof UiElementEditPart) { - return new NonResizableSelectionEditPolicy((UiElementEditPart) child); - } - return null; - } - - @Override - protected Command getCreateCommand(CreateRequest request) { - // We store the ElementDescriptor in the request.factory.type - Object newType = request.getNewObjectType(); - if (newType instanceof ElementDescriptor) { - Point where = request.getLocation().getCopy(); - Point origin = getLayoutContainer().getClientArea().getLocation(); - where.translate(origin.getNegated()); - - // The host is the EditPart where this policy is installed, - // e.g. this UiElementEditPart. - EditPart host = getHost(); - if (host instanceof UiElementEditPart) { - - return new ElementCreateCommand((ElementDescriptor) newType, - (UiElementEditPart) host, - where); - } - } - - return null; - } - - @Override - protected Command getMoveChildrenCommand(Request request) { - // TODO Auto-generated method stub - return null; - } - - @Override - public void showLayoutTargetFeedback(Request request) { - super.showLayoutTargetFeedback(request); - - // for debugging - // System.out.println("target: " + request.toString() + " -- " + layoutEditPart.getUiNode().getBreadcrumbTrailDescription(false)); - - if (layoutEditPart instanceof UiLayoutEditPart && - request instanceof DropRequest) { - Point where = ((DropRequest) request).getLocation().getCopy(); - Point origin = getLayoutContainer().getClientArea().getLocation(); - where.translate(origin.getNegated()); - - ((UiLayoutEditPart) layoutEditPart).showDropTarget(where); - } - } - - @Override - protected void eraseLayoutTargetFeedback(Request request) { - super.eraseLayoutTargetFeedback(request); - if (layoutEditPart instanceof UiLayoutEditPart) { - ((UiLayoutEditPart) layoutEditPart).hideDropTarget(); - } - } - - @Override - protected IFigure createSizeOnDropFeedback(CreateRequest createRequest) { - // TODO understand if this is useful for us or remove - return super.createSizeOnDropFeedback(createRequest); - } - - }); - } - - protected static class NonResizableSelectionEditPolicy extends SelectionEditPolicy { - - private final UiElementEditPart mEditPart; - - public NonResizableSelectionEditPolicy(UiElementEditPart editPart) { - mEditPart = editPart; - } - - @Override - protected void hideSelection() { - mEditPart.hideSelection(); - } - - @Override - protected void showSelection() { - mEditPart.showSelection(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementTreeEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementTreeEditPart.java deleted file mode 100644 index fd788dd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementTreeEditPart.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.gef.editparts.AbstractTreeEditPart; -import org.eclipse.swt.graphics.Image; -import org.eclipse.ui.views.contentoutline.IContentOutlinePage; - -/** - * Base {@link AbstractTreeEditPart} to represent {@link UiElementNode} objects in the - * {@link IContentOutlinePage} linked to the layout editor. - */ -public class UiElementTreeEditPart extends AbstractTreeEditPart { - - public UiElementTreeEditPart(UiElementNode uiElementNode) { - setModel(uiElementNode); - } - - @Override - protected void createEditPolicies() { - // TODO Auto-generated method stub - super.createEditPolicies(); - } - - @Override - protected Image getImage() { - return getUiNode().getDescriptor().getIcon(); - } - - @Override - protected String getText() { - return getUiNode().getShortDescription(); - } - - @Override - public void activate() { - if (!isActive()) { - super.activate(); - // TODO - } - } - - @Override - public void deactivate() { - if (isActive()) { - super.deactivate(); - // TODO - } - } - - /** - * Returns the casted model object represented by this {@link AbstractTreeEditPart}. - */ - protected UiElementNode getUiNode() { - return (UiElementNode)getModel(); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementTreeEditPartFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementTreeEditPartFactory.java deleted file mode 100644 index de6c404..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementTreeEditPartFactory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.gef.EditPart; -import org.eclipse.gef.EditPartFactory; -import org.eclipse.gef.editparts.AbstractTreeEditPart; -import org.eclipse.ui.views.contentoutline.IContentOutlinePage; - -/** - * {@link EditPartFactory} to create {@link AbstractTreeEditPart} for {@link UiElementNode} objects. - * These objects are used in the {@link IContentOutlinePage} linked to the layout editor. - */ -public class UiElementTreeEditPartFactory implements EditPartFactory { - - public EditPart createEditPart(EditPart context, Object model) { - if (model instanceof UiDocumentNode) { - return new UiDocumentTreeEditPart((UiDocumentNode) model); - } else if (model instanceof UiElementNode) { - UiElementNode node = (UiElementNode) model; - if (node.getDescriptor().hasChildren()) { - return new UiLayoutTreeEditPart(node); - } else { - return new UiViewTreeEditPart(node); - } - } - return null; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementsEditPartFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementsEditPartFactory.java deleted file mode 100644 index 18dcd9c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiElementsEditPartFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.gef.EditPart; -import org.eclipse.gef.EditPartFactory; -import org.eclipse.swt.widgets.Display; - -/** - * A factory that returns the appropriate {@link EditPart} for a given model object. - * <p/> - * The only model objects we use are {@link UiElementNode} objects and they are - * edited using {@link UiElementEditPart}. - */ -public class UiElementsEditPartFactory implements EditPartFactory { - - private Display mDisplay; - - public UiElementsEditPartFactory(Display display) { - mDisplay = display; - } - - public EditPart createEditPart(EditPart context, Object model) { - if (model instanceof UiDocumentNode) { - return new UiDocumentEditPart((UiDocumentNode) model, mDisplay); - } else if (model instanceof UiElementNode) { - UiElementNode node = (UiElementNode) model; - - if (node.getDescriptor().hasChildren()) { - return new UiLayoutEditPart(node); - } - - return new UiViewEditPart(node); - } - return null; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiLayoutEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiLayoutEditPart.java deleted file mode 100644 index 43a70a5..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiLayoutEditPart.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.draw2d.IFigure; -import org.eclipse.draw2d.XYLayout; -import org.eclipse.draw2d.geometry.Point; -import org.eclipse.gef.EditPolicy; -import org.eclipse.gef.commands.Command; -import org.eclipse.gef.editpolicies.ContainerEditPolicy; -import org.eclipse.gef.requests.CreateRequest; - -/** - * Graphical edit part for an {@link UiElementNode} that represents a ViewLayout. - * <p/> - * It acts as a simple container. - */ -public final class UiLayoutEditPart extends UiElementEditPart { - - static class HighlightInfo { - public boolean drawDropBorder; - public UiElementEditPart[] childParts; - public Point anchorPoint; - public Point linePoints[]; - - public final Point tempPoints[] = new Point[] { new Point(), new Point() }; - - public void clear() { - drawDropBorder = false; - childParts = null; - anchorPoint = null; - linePoints = null; - } - } - - private final HighlightInfo mHighlightInfo = new HighlightInfo(); - - public UiLayoutEditPart(UiElementNode uiElementNode) { - super(uiElementNode); - } - - @Override - protected void createEditPolicies() { - super.createEditPolicies(); - - installEditPolicy(EditPolicy.CONTAINER_ROLE, new ContainerEditPolicy() { - @Override - protected Command getCreateCommand(CreateRequest request) { - return null; - } - }); - - installLayoutEditPolicy(this); - } - - @Override - protected IFigure createFigure() { - IFigure f = new LayoutFigure(); - f.setLayoutManager(new XYLayout()); - return f; - } - - @Override - protected void showSelection() { - IFigure f = getFigure(); - if (f instanceof ElementFigure) { - ((ElementFigure) f).setSelected(true); - } - } - - @Override - protected void hideSelection() { - IFigure f = getFigure(); - if (f instanceof ElementFigure) { - ((ElementFigure) f).setSelected(false); - } - } - - public void showDropTarget(Point where) { - if (where != null) { - mHighlightInfo.clear(); - mHighlightInfo.drawDropBorder = true; - DropFeedback.computeDropFeedback(this, mHighlightInfo, where); - - IFigure f = getFigure(); - if (f instanceof LayoutFigure) { - ((LayoutFigure) f).setHighlighInfo(mHighlightInfo); - } - } - } - - public void hideDropTarget() { - mHighlightInfo.clear(); - IFigure f = getFigure(); - if (f instanceof LayoutFigure) { - ((LayoutFigure) f).setHighlighInfo(mHighlightInfo); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiLayoutTreeEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiLayoutTreeEditPart.java deleted file mode 100644 index 4359e23..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiLayoutTreeEditPart.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import java.util.List; - -/** - * Implementation of {@link UiElementTreeEditPart} for layout objects. - */ -public class UiLayoutTreeEditPart extends UiElementTreeEditPart { - - public UiLayoutTreeEditPart(UiElementNode node) { - super(node); - } - - @SuppressWarnings("unchecked") - @Override - protected List getModelChildren() { - return getUiNode().getUiChildren(); - } - - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiViewEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiViewEditPart.java deleted file mode 100644 index 05329f3..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiViewEditPart.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.draw2d.IFigure; -import org.eclipse.draw2d.XYLayout; - -/** - * Graphical edit part for an {@link UiElementNode} that represents a View. - */ -public class UiViewEditPart extends UiElementEditPart { - - public UiViewEditPart(UiElementNode uiElementNode) { - super(uiElementNode); - } - - @Override - protected IFigure createFigure() { - IFigure f = new ElementFigure(); - f.setLayoutManager(new XYLayout()); - return f; - } - - @Override - protected void showSelection() { - IFigure f = getFigure(); - if (f instanceof ElementFigure) { - ((ElementFigure) f).setSelected(true); - } - } - - @Override - protected void hideSelection() { - IFigure f = getFigure(); - if (f instanceof ElementFigure) { - ((ElementFigure) f).setSelected(false); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiViewTreeEditPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiViewTreeEditPart.java deleted file mode 100644 index 62b5e8a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/parts/UiViewTreeEditPart.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.parts; - -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * Implementation of {@link UiElementTreeEditPart} for view objects. - */ -public class UiViewTreeEditPart extends UiElementTreeEditPart { - - public UiViewTreeEditPart(UiElementNode node) { - super(node); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java deleted file mode 100644 index 1bf5d5a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/uimodel/UiViewElementNode.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.layout.uimodel; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IProject; - -import java.util.List; - -/** - * Specialized version of {@link UiElementNode} for the {@link ViewElementDescriptor}s. - */ -public class UiViewElementNode extends UiElementNode { - - private AttributeDescriptor[] mCachedAttributeDescriptors; - - public UiViewElementNode(ViewElementDescriptor elementDescriptor) { - super(elementDescriptor); - } - - /** - * Returns an AttributeDescriptor array that depends on the current UiParent. - * <p/> - * The array merges both "direct" attributes with the descriptor layout attributes. - * The array instance is cached and cleared if the UiParent is changed. - */ - @Override - public AttributeDescriptor[] getAttributeDescriptors() { - if (mCachedAttributeDescriptors != null) { - return mCachedAttributeDescriptors; - } - - UiElementNode ui_parent = getUiParent(); - AttributeDescriptor[] direct_attrs = super.getAttributeDescriptors(); - mCachedAttributeDescriptors = direct_attrs; - - AttributeDescriptor[] layout_attrs = null; - boolean need_xmlns = false; - - if (ui_parent instanceof UiDocumentNode) { - // Limitation: right now the layout behaves as if everything was - // owned by a FrameLayout. - // TODO replace by something user-configurable. - - List<ElementDescriptor> layoutDescriptors = null; - IProject project = getEditor().getProject(); - if (project != null) { - Sdk currentSdk = Sdk.getCurrent(); - IAndroidTarget target = currentSdk.getTarget(project); - if (target != null) { - AndroidTargetData data = currentSdk.getTargetData(target); - layoutDescriptors = data.getLayoutDescriptors().getLayoutDescriptors(); - } - } - - if (layoutDescriptors != null) { - for (ElementDescriptor desc : layoutDescriptors) { - if (desc instanceof ViewElementDescriptor && - desc.getXmlName().equals(AndroidConstants.CLASS_FRAMELAYOUT)) { - layout_attrs = ((ViewElementDescriptor) desc).getLayoutAttributes(); - need_xmlns = true; - break; - } - } - } - } else if (ui_parent instanceof UiViewElementNode){ - layout_attrs = - ((ViewElementDescriptor) ui_parent.getDescriptor()).getLayoutAttributes(); - } - - if (layout_attrs == null || layout_attrs.length == 0) { - return mCachedAttributeDescriptors; - } - - mCachedAttributeDescriptors = - new AttributeDescriptor[direct_attrs.length + - layout_attrs.length + - (need_xmlns ? 1 : 0)]; - System.arraycopy(direct_attrs, 0, - mCachedAttributeDescriptors, 0, - direct_attrs.length); - System.arraycopy(layout_attrs, 0, - mCachedAttributeDescriptors, direct_attrs.length, - layout_attrs.length); - if (need_xmlns) { - AttributeDescriptor desc = new XmlnsAttributeDescriptor( - "android", //$NON-NLS-1$ - SdkConstants.NS_RESOURCES); - mCachedAttributeDescriptors[direct_attrs.length + layout_attrs.length] = desc; - } - - return mCachedAttributeDescriptors; - } - - /** - * Sets the parent of this UI node. - * <p/> - * Also removes the cached AttributeDescriptor array that depends on the current UiParent. - */ - @Override - protected void setUiParent(UiElementNode parent) { - super.setUiParent(parent); - mCachedAttributeDescriptors = null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestContentAssist.java deleted file mode 100644 index b40e458..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestContentAssist.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidContentAssist; - -/** - * Content Assist Processor for AndroidManifest.xml - */ -final class ManifestContentAssist extends AndroidContentAssist { - - /** - * Constructor for ManifestContentAssist - */ - public ManifestContentAssist() { - super(AndroidTargetData.DESCRIPTOR_MANIFEST); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestEditor.java deleted file mode 100644 index d0f8d7b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestEditor.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidXPathFactory; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.manifest.pages.ApplicationPage; -import com.android.ide.eclipse.editors.manifest.pages.InstrumentationPage; -import com.android.ide.eclipse.editors.manifest.pages.OverviewPage; -import com.android.ide.eclipse.editors.manifest.pages.PermissionPage; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.FileEditorInput; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -import java.util.List; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; - -/** - * Multi-page form editor for AndroidManifest.xml. - */ -public final class ManifestEditor extends AndroidEditor { - private final static String EMPTY = ""; //$NON-NLS-1$ - - - /** Root node of the UI element hierarchy */ - private UiElementNode mUiManifestNode; - /** The Application Page tab */ - private ApplicationPage mAppPage; - /** The Overview Manifest Page tab */ - private OverviewPage mOverviewPage; - /** The Permission Page tab */ - private PermissionPage mPermissionPage; - /** The Instrumentation Page tab */ - private InstrumentationPage mInstrumentationPage; - - private IFileListener mMarkerMonitor; - - - /** - * Creates the form editor for AndroidManifest.xml. - */ - public ManifestEditor() { - super(); - } - - @Override - public void dispose() { - super.dispose(); - - ResourceMonitor.getMonitor().removeFileListener(mMarkerMonitor); - } - - /** - * Return the root node of the UI element hierarchy, which here - * is the "manifest" node. - */ - @Override - public UiElementNode getUiRootNode() { - return mUiManifestNode; - } - - /** - * Returns the Manifest descriptors for the file being edited. - */ - public AndroidManifestDescriptors getManifestDescriptors() { - AndroidTargetData data = getTargetData(); - if (data != null) { - return data.getManifestDescriptors(); - } - - return null; - } - - // ---- Base Class Overrides ---- - - /** - * Returns whether the "save as" operation is supported by this editor. - * <p/> - * Save-As is a valid operation for the ManifestEditor since it acts on a - * single source file. - * - * @see IEditorPart - */ - @Override - public boolean isSaveAsAllowed() { - return true; - } - - /** - * Creates the various form pages. - */ - @Override - protected void createFormPages() { - try { - addPage(mOverviewPage = new OverviewPage(this)); - addPage(mAppPage = new ApplicationPage(this)); - addPage(mPermissionPage = new PermissionPage(this)); - addPage(mInstrumentationPage = new InstrumentationPage(this)); - } catch (PartInitException e) { - AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$ - } - } - - /* (non-java doc) - * Change the tab/title name to include the project name. - */ - @Override - protected void setInput(IEditorInput input) { - super.setInput(input); - IFile inputFile = getInputFile(); - if (inputFile != null) { - startMonitoringMarkers(); - setPartName(String.format("%1$s Manifest", inputFile.getProject().getName())); - } - } - - /** - * Processes the new XML Model, which XML root node is given. - * - * @param xml_doc The XML document, if available, or null if none exists. - */ - @Override - protected void xmlModelChanged(Document xml_doc) { - // create the ui root node on demand. - initUiRootNode(false /*force*/); - - loadFromXml(xml_doc); - - super.xmlModelChanged(xml_doc); - } - - private void loadFromXml(Document xmlDoc) { - mUiManifestNode.setXmlDocument(xmlDoc); - if (xmlDoc != null) { - ElementDescriptor manifest_desc = mUiManifestNode.getDescriptor(); - try { - XPath xpath = AndroidXPathFactory.newXPath(); - Node node = (Node) xpath.evaluate("/" + manifest_desc.getXmlName(), //$NON-NLS-1$ - xmlDoc, - XPathConstants.NODE); - assert node != null && node.getNodeName().equals(manifest_desc.getXmlName()); - - // Refresh the manifest UI node and all its descendants - mUiManifestNode.loadFromXmlNode(node); - } catch (XPathExpressionException e) { - AdtPlugin.log(e, "XPath error when trying to find '%s' element in XML.", //$NON-NLS-1$ - manifest_desc.getXmlName()); - } - } - } - - private void onDescriptorsChanged(UiElementNode oldManifestNode) { - mUiManifestNode.reloadFromXmlNode(oldManifestNode.getXmlNode()); - - if (mOverviewPage != null) { - mOverviewPage.refreshUiApplicationNode(); - } - - if (mAppPage != null) { - mAppPage.refreshUiApplicationNode(); - } - - if (mPermissionPage != null) { - mPermissionPage.refreshUiNode(); - } - - if (mInstrumentationPage != null) { - mInstrumentationPage.refreshUiNode(); - } - } - - /** - * Reads and processes the current markers and adds a listener for marker changes. - */ - private void startMonitoringMarkers() { - final IFile inputFile = getInputFile(); - if (inputFile != null) { - updateFromExistingMarkers(inputFile); - - mMarkerMonitor = new IFileListener() { - public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { - if (file.equals(inputFile)) { - processMarkerChanges(markerDeltas); - } - } - }; - - ResourceMonitor.getMonitor().addFileListener(mMarkerMonitor, IResourceDelta.CHANGED); - } - } - - /** - * Processes the markers of the specified {@link IFile} and updates the error status of - * {@link UiElementNode}s and {@link UiAttributeNode}s. - * @param inputFile the file being edited. - */ - private void updateFromExistingMarkers(IFile inputFile) { - try { - // get the markers for the file - IMarker[] markers = inputFile.findMarkers(AndroidConstants.MARKER_ANDROID, true, - IResource.DEPTH_ZERO); - - AndroidManifestDescriptors desc = getManifestDescriptors(); - if (desc != null) { - ElementDescriptor appElement = desc.getApplicationElement(); - - if (appElement != null) { - UiElementNode app_ui_node = mUiManifestNode.findUiChildNode( - appElement.getXmlName()); - List<UiElementNode> children = app_ui_node.getUiChildren(); - - for (IMarker marker : markers) { - processMarker(marker, children, IResourceDelta.ADDED); - } - } - } - - } catch (CoreException e) { - // findMarkers can throw an exception, in which case, we'll do nothing. - } - } - - /** - * Processes a {@link IMarker} change. - * @param markerDeltas the list of {@link IMarkerDelta} - */ - private void processMarkerChanges(IMarkerDelta[] markerDeltas) { - AndroidManifestDescriptors descriptors = getManifestDescriptors(); - if (descriptors != null && descriptors.getApplicationElement() != null) { - UiElementNode app_ui_node = mUiManifestNode.findUiChildNode( - descriptors.getApplicationElement().getXmlName()); - List<UiElementNode> children = app_ui_node.getUiChildren(); - - for (IMarkerDelta markerDelta : markerDeltas) { - processMarker(markerDelta.getMarker(), children, markerDelta.getKind()); - } - } - } - - /** - * Processes a new/old/updated marker. - * @param marker The marker being added/removed/changed - * @param nodeList the list of activity/service/provider/receiver nodes. - * @param kind the change kind. Can be {@link IResourceDelta#ADDED}, - * {@link IResourceDelta#REMOVED}, or {@link IResourceDelta#CHANGED} - */ - private void processMarker(IMarker marker, List<UiElementNode> nodeList, int kind) { - // get the data from the marker - String nodeType = marker.getAttribute(AndroidConstants.MARKER_ATTR_TYPE, EMPTY); - if (nodeType == EMPTY) { - return; - } - - String className = marker.getAttribute(AndroidConstants.MARKER_ATTR_CLASS, EMPTY); - if (className == EMPTY) { - return; - } - - for (UiElementNode ui_node : nodeList) { - if (ui_node.getDescriptor().getXmlName().equals(nodeType)) { - for (UiAttributeNode attr : ui_node.getUiAttributes()) { - if (attr.getDescriptor().getXmlLocalName().equals( - AndroidManifestDescriptors.ANDROID_NAME_ATTR)) { - if (attr.getCurrentValue().equals(className)) { - if (kind == IResourceDelta.REMOVED) { - attr.setHasError(false); - } else { - attr.setHasError(true); - } - return; - } - } - } - } - } - } - - /** - * Creates the initial UI Root Node, including the known mandatory elements. - * @param force if true, a new UiManifestNode is recreated even if it already exists. - */ - @Override - protected void initUiRootNode(boolean force) { - // The manifest UI node is always created, even if there's no corresponding XML node. - if (mUiManifestNode != null && force == false) { - return; - } - - - AndroidManifestDescriptors manifestDescriptor = getManifestDescriptors(); - - if (manifestDescriptor != null) { - // save the old manifest node if it exists - UiElementNode oldManifestNode = mUiManifestNode; - - ElementDescriptor manifestElement = manifestDescriptor.getManifestElement(); - mUiManifestNode = manifestElement.createUiNode(); - mUiManifestNode.setEditor(this); - - // Similarly, always create the /manifest/application and /manifest/uses-sdk nodes - ElementDescriptor appElement = manifestDescriptor.getApplicationElement(); - boolean present = false; - for (UiElementNode ui_node : mUiManifestNode.getUiChildren()) { - if (ui_node.getDescriptor() == appElement) { - present = true; - break; - } - } - if (!present) { - mUiManifestNode.appendNewUiChild(appElement); - } - - appElement = manifestDescriptor.getUsesSdkElement(); - present = false; - for (UiElementNode ui_node : mUiManifestNode.getUiChildren()) { - if (ui_node.getDescriptor() == appElement) { - present = true; - break; - } - } - if (!present) { - mUiManifestNode.appendNewUiChild(appElement); - } - - if (oldManifestNode != null) { - onDescriptorsChanged(oldManifestNode); - } - } else { - // create a dummy descriptor/uinode until we have real descriptors - ElementDescriptor desc = new ElementDescriptor("manifest", //$NON-NLS-1$ - "temporary descriptors due to missing decriptors", //$NON-NLS-1$ - null /*tooltip*/, null /*sdk_url*/, null /*attributes*/, - null /*children*/, false /*mandatory*/); - mUiManifestNode = desc.createUiNode(); - mUiManifestNode.setEditor(this); - } - } - - /** - * Returns the {@link IFile} being edited, or <code>null</code> if it couldn't be computed. - */ - private IFile getInputFile() { - IEditorInput input = getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput) input; - return fileInput.getFile(); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestEditorContributor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestEditorContributor.java deleted file mode 100644 index 911faa1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestEditorContributor.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest; - -import org.eclipse.jface.action.IAction; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.ide.IDEActionFactory; -import org.eclipse.ui.part.MultiPageEditorActionBarContributor; -import org.eclipse.ui.texteditor.ITextEditor; -import org.eclipse.ui.texteditor.ITextEditorActionConstants; - -/** - * Manages the installation/deinstallation of global actions for multi-page - * editors. Responsible for the redirection of global actions to the active - * editor. Multi-page contributor replaces the contributors for the individual - * editors in the multi-page editor. - * - * TODO: Doesn't look like we need this. Remove it if not needed. - * @deprecated - */ -final class ManifestEditorContributor extends MultiPageEditorActionBarContributor { - private IEditorPart mActiveEditorPart; - - /** - * Creates a multi-page contributor. - * - * Marked as Private so it can't be instanciated. This is a cheap way to make sure - * it's not being used. As noted in constructor, should be removed if not used. - * @deprecated - */ - private ManifestEditorContributor() { - super(); - } - - /** - * Returns the action registed with the given text editor. - * - * @return IAction or null if editor is null. - */ - protected IAction getAction(ITextEditor editor, String actionID) { - return (editor == null ? null : editor.getAction(actionID)); - } - - /* - * (non-JavaDoc) Method declared in - * AbstractMultiPageEditorActionBarContributor. - */ - - @Override - public void setActivePage(IEditorPart part) { - if (mActiveEditorPart == part) - return; - - mActiveEditorPart = part; - - IActionBars actionBars = getActionBars(); - if (actionBars != null) { - - ITextEditor editor = - (part instanceof ITextEditor) ? (ITextEditor)part : null; - - actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), - getAction(editor, ITextEditorActionConstants.DELETE)); - actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), - getAction(editor, ITextEditorActionConstants.UNDO)); - actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), - getAction(editor, ITextEditorActionConstants.REDO)); - actionBars.setGlobalActionHandler(ActionFactory.CUT.getId(), - getAction(editor, ITextEditorActionConstants.CUT)); - actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), - getAction(editor, ITextEditorActionConstants.COPY)); - actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), - getAction(editor, ITextEditorActionConstants.PASTE)); - actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), - getAction(editor, ITextEditorActionConstants.SELECT_ALL)); - actionBars.setGlobalActionHandler(ActionFactory.FIND.getId(), - getAction(editor, ITextEditorActionConstants.FIND)); - actionBars.setGlobalActionHandler( - IDEActionFactory.BOOKMARK.getId(), getAction(editor, - IDEActionFactory.BOOKMARK.getId())); - actionBars.updateActionBars(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestSourceViewerConfig.java deleted file mode 100644 index e33e1ef..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/ManifestSourceViewerConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest; - - -import com.android.ide.eclipse.editors.AndroidSourceViewerConfig; - -/** - * Source Viewer Configuration that calls in ManifestContentAssist. - */ -public final class ManifestSourceViewerConfig extends AndroidSourceViewerConfig { - - public ManifestSourceViewerConfig() { - super(new ManifestContentAssist()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java deleted file mode 100644 index 61b73a2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.ListAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ReferenceAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.runtime.IStatus; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.Map.Entry; - - -/** - * Complete description of the AndroidManifest.xml structure. - * <p/> - * The root element are static instances which always exists. - * However their sub-elements and attributes are created only when the SDK changes or is - * loaded the first time. - */ -public final class AndroidManifestDescriptors implements IDescriptorProvider { - - private static final String MANIFEST_NODE_NAME = "manifest"; //$NON-NLS-1$ - private static final String ANDROID_MANIFEST_STYLEABLE = "AndroidManifest"; //$NON-NLS-1$ - - // Public attributes names, attributes descriptors and elements descriptors - - public static final String ANDROID_LABEL_ATTR = "label"; //$NON-NLS-1$ - public static final String ANDROID_NAME_ATTR = "name"; //$NON-NLS-1$ - public static final String PACKAGE_ATTR = "package"; //$NON-NLS-1$ - - /** The {@link ElementDescriptor} for the root Manifest element. */ - private final ElementDescriptor MANIFEST_ELEMENT; - /** The {@link ElementDescriptor} for the root Application element. */ - private final ElementDescriptor APPLICATION_ELEMENT; - - /** The {@link ElementDescriptor} for the root Instrumentation element. */ - private final ElementDescriptor INTRUMENTATION_ELEMENT; - /** The {@link ElementDescriptor} for the root Permission element. */ - private final ElementDescriptor PERMISSION_ELEMENT; - /** The {@link ElementDescriptor} for the root UsesPermission element. */ - private final ElementDescriptor USES_PERMISSION_ELEMENT; - /** The {@link ElementDescriptor} for the root UsesSdk element. */ - private final ElementDescriptor USES_SDK_ELEMENT; - - /** The {@link ElementDescriptor} for the root PermissionGroup element. */ - private final ElementDescriptor PERMISSION_GROUP_ELEMENT; - /** The {@link ElementDescriptor} for the root PermissionTree element. */ - private final ElementDescriptor PERMISSION_TREE_ELEMENT; - - /** Private package attribute for the manifest element. Needs to be handled manually. */ - private final TextAttributeDescriptor PACKAGE_ATTR_DESC; - - public AndroidManifestDescriptors() { - APPLICATION_ELEMENT = createElement("application", null, true); //$NON-NLS-1$ + no child & mandatory - INTRUMENTATION_ELEMENT = createElement("instrumentation"); //$NON-NLS-1$ - - PERMISSION_ELEMENT = createElement("permission"); //$NON-NLS-1$ - USES_PERMISSION_ELEMENT = createElement("uses-permission"); //$NON-NLS-1$ - USES_SDK_ELEMENT = createElement("uses-sdk", null, true); //$NON-NLS-1$ + no child & mandatory - - PERMISSION_GROUP_ELEMENT = createElement("permission-group"); //$NON-NLS-1$ - PERMISSION_TREE_ELEMENT = createElement("permission-tree"); //$NON-NLS-1$ - - MANIFEST_ELEMENT = createElement( - MANIFEST_NODE_NAME, // xml name - new ElementDescriptor[] { - APPLICATION_ELEMENT, - INTRUMENTATION_ELEMENT, - PERMISSION_ELEMENT, - USES_PERMISSION_ELEMENT, - PERMISSION_GROUP_ELEMENT, - PERMISSION_TREE_ELEMENT, - USES_SDK_ELEMENT, - }, - true /* mandatory */); - - // The "package" attribute is treated differently as it doesn't have the standard - // Android XML namespace. - PACKAGE_ATTR_DESC = new PackageAttributeDescriptor(PACKAGE_ATTR, - "Package", - null /* nsUri */, - "This attribute gives a unique name for the package, using a Java-style naming convention to avoid name collisions.\nFor example, applications published by Google could have names of the form com.google.app.appname"); - } - - public ElementDescriptor[] getRootElementDescriptors() { - return new ElementDescriptor[] { MANIFEST_ELEMENT }; - } - - public ElementDescriptor getDescriptor() { - return getManifestElement(); - } - - public ElementDescriptor getApplicationElement() { - return APPLICATION_ELEMENT; - } - - public ElementDescriptor getManifestElement() { - return MANIFEST_ELEMENT; - } - - public ElementDescriptor getUsesSdkElement() { - return USES_SDK_ELEMENT; - } - - public ElementDescriptor getInstrumentationElement() { - return INTRUMENTATION_ELEMENT; - } - - public ElementDescriptor getPermissionElement() { - return PERMISSION_ELEMENT; - } - - public ElementDescriptor getUsesPermissionElement() { - return USES_PERMISSION_ELEMENT; - } - - public ElementDescriptor getPermissionGroupElement() { - return PERMISSION_GROUP_ELEMENT; - } - - public ElementDescriptor getPermissionTreeElement() { - return PERMISSION_TREE_ELEMENT; - } - - /** - * Updates the document descriptor. - * <p/> - * It first computes the new children of the descriptor and then updates them - * all at once. - * - * @param manifestMap The map style => attributes from the attrs_manifest.xml file - */ - public synchronized void updateDescriptors( - Map<String, DeclareStyleableInfo> manifestMap) { - - XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor( - "android", //$NON-NLS-1$ - SdkConstants.NS_RESOURCES); - - // -- setup the required attributes overrides -- - - Set<String> required = new HashSet<String>(); - required.add("provider/authorities"); //$NON-NLS-1$ - - // -- setup the various attribute format overrides -- - - // The key for each override is "element1,element2,.../attr-xml-local-name" or - // "*/attr-xml-local-name" to match the attribute in any element. - - Map<String, Object> overrides = new HashMap<String, Object>(); - - overrides.put("*/icon", new DescriptorsUtils.ITextAttributeCreator() { //$NON-NLS-1$ - public TextAttributeDescriptor create(String xmlName, String uiName, String nsUri, - String tooltip) { - return new ReferenceAttributeDescriptor( - ResourceType.DRAWABLE, - xmlName, uiName, nsUri, - tooltip); - } - }); - - overrides.put("*/theme", ThemeAttributeDescriptor.class); //$NON-NLS-1$ - overrides.put("*/permission", ListAttributeDescriptor.class); //$NON-NLS-1$ - overrides.put("*/targetPackage", PackageAttributeDescriptor.class); //$NON-NLS-1$ - - overrides.put("action,category,uses-permission/" + ANDROID_NAME_ATTR, //$NON-NLS-1$ - ListAttributeDescriptor.class); - overrides.put("application/" + ANDROID_NAME_ATTR, ApplicationAttributeDescriptor.class); //$NON-NLS-1$ - - overrideClassName(overrides, "activity", AndroidConstants.CLASS_ACTIVITY); //$NON-NLS-1$ - overrideClassName(overrides, "receiver", AndroidConstants.CLASS_BROADCASTRECEIVER); //$NON-NLS-1$ - overrideClassName(overrides, "service", AndroidConstants.CLASS_SERVICE); //$NON-NLS-1$ - overrideClassName(overrides, "provider", AndroidConstants.CLASS_CONTENTPROVIDER); //$NON-NLS-1$ - - // -- list element nodes already created -- - // These elements are referenced by already opened editors, so we want to update them - // but not re-create them when reloading an SDK on the fly. - - HashMap<String, ElementDescriptor> elementDescs = - new HashMap<String, ElementDescriptor>(); - elementDescs.put(MANIFEST_ELEMENT.getXmlLocalName(), MANIFEST_ELEMENT); - elementDescs.put(APPLICATION_ELEMENT.getXmlLocalName(), APPLICATION_ELEMENT); - elementDescs.put(INTRUMENTATION_ELEMENT.getXmlLocalName(), INTRUMENTATION_ELEMENT); - elementDescs.put(PERMISSION_ELEMENT.getXmlLocalName(), PERMISSION_ELEMENT); - elementDescs.put(USES_PERMISSION_ELEMENT.getXmlLocalName(), USES_PERMISSION_ELEMENT); - elementDescs.put(USES_SDK_ELEMENT.getXmlLocalName(), USES_SDK_ELEMENT); - elementDescs.put(PERMISSION_GROUP_ELEMENT.getXmlLocalName(), PERMISSION_GROUP_ELEMENT); - elementDescs.put(PERMISSION_TREE_ELEMENT.getXmlLocalName(), PERMISSION_TREE_ELEMENT); - - // -- - - inflateElement(manifestMap, - overrides, - required, - elementDescs, - MANIFEST_ELEMENT, - "AndroidManifest"); //$NON-NLS-1$ - insertAttribute(MANIFEST_ELEMENT, PACKAGE_ATTR_DESC); - - sanityCheck(manifestMap, MANIFEST_ELEMENT); - } - - /** - * Sets up an attribute override for ANDROID_NAME_ATTR using a ClassAttributeDescriptor - * with the specified class name. - */ - private static void overrideClassName(Map<String, Object> overrides, - String elementName, final String className) { - overrides.put(elementName + "/" + ANDROID_NAME_ATTR, - new DescriptorsUtils.ITextAttributeCreator() { - public TextAttributeDescriptor create(String xmlName, String uiName, String nsUri, - String tooltip) { - if (AndroidConstants.CLASS_ACTIVITY.equals(className)) { - return new ClassAttributeDescriptor( - className, - PostActivityCreationAction.getAction(), - xmlName, uiName + "*", //$NON-NLS-1$ - nsUri, - tooltip, - true /*mandatory */); - } else if (AndroidConstants.CLASS_BROADCASTRECEIVER.equals(className)) { - return new ClassAttributeDescriptor( - className, - PostReceiverCreationAction.getAction(), - xmlName, uiName + "*", //$NON-NLS-1$ - nsUri, - tooltip, - true /*mandatory */); - - } else { - return new ClassAttributeDescriptor( - className, - xmlName, uiName + "*", //$NON-NLS-1$ - nsUri, - tooltip, - true /*mandatory */); - } - } - }); - } - - /** - * Returns a new ElementDescriptor constructed from the information given here - * and the javadoc & attributes extracted from the style map if any. - * <p/> - * Creates an element with no attribute overrides. - */ - private ElementDescriptor createElement( - String xmlName, - ElementDescriptor[] childrenElements, - boolean mandatory) { - // Creates an element with no attribute overrides. - String styleName = guessStyleName(xmlName); - String sdkUrl = DescriptorsUtils.MANIFEST_SDK_URL + styleName; - String uiName = getUiName(xmlName); - - ElementDescriptor element = new ManifestElementDescriptor(xmlName, uiName, null, sdkUrl, - null, childrenElements, mandatory); - - return element; - } - - /** - * Returns a new ElementDescriptor constructed from its XML local name. - * <p/> - * This version creates an element not mandatory. - */ - private ElementDescriptor createElement(String xmlName) { - // Creates an element with no child and not mandatory - return createElement(xmlName, null, false); - } - - /** - * Inserts an attribute in this element attribute list if it is not present there yet - * (based on the attribute XML name.) - * The attribute is inserted at the beginning of the attribute list. - */ - private void insertAttribute(ElementDescriptor element, AttributeDescriptor newAttr) { - AttributeDescriptor[] attributes = element.getAttributes(); - for (AttributeDescriptor attr : attributes) { - if (attr.getXmlLocalName().equals(newAttr.getXmlLocalName())) { - return; - } - } - - AttributeDescriptor[] newArray = new AttributeDescriptor[attributes.length + 1]; - newArray[0] = newAttr; - System.arraycopy(attributes, 0, newArray, 1, attributes.length); - element.setAttributes(newArray); - } - - /** - * "Inflates" the properties of an {@link ElementDescriptor} from the styleable declaration. - * <p/> - * This first creates all the attributes for the given ElementDescriptor. - * It then finds all children of the descriptor, inflate them recursively and set them - * as child to this ElementDescriptor. - * - * @param styleMap The input styleable map for manifest elements & attributes. - * @param overrides A list of attribute overrides (to customize the type of the attribute - * descriptors). - * @param requiredAttributes Set of attributes to be marked as required. - * @param existingElementDescs A map of already created element descriptors, keyed by - * XML local name. This is used to use the static elements created initially by this - * class, which are referenced directly by editors (so that reloading an SDK won't - * break these references). - * @param elemDesc The current {@link ElementDescriptor} to inflate. - * @param styleName The name of the {@link ElementDescriptor} to inflate. Its XML local name - * will be guessed automatically from the style name. - */ - private void inflateElement( - Map<String, DeclareStyleableInfo> styleMap, - Map<String, Object> overrides, - Set<String> requiredAttributes, - HashMap<String, ElementDescriptor> existingElementDescs, - ElementDescriptor elemDesc, - String styleName) { - assert elemDesc != null; - assert styleName != null; - - // define attributes - DeclareStyleableInfo style = styleMap != null ? styleMap.get(styleName) : null; - if (style != null) { - ArrayList<AttributeDescriptor> attrDescs = new ArrayList<AttributeDescriptor>(); - DescriptorsUtils.appendAttributes(attrDescs, - elemDesc.getXmlLocalName(), - SdkConstants.NS_RESOURCES, - style.getAttributes(), - requiredAttributes, - overrides); - elemDesc.setTooltip(style.getJavaDoc()); - elemDesc.setAttributes(attrDescs.toArray(new AttributeDescriptor[attrDescs.size()])); - } - - // find all elements that have this one as parent - ArrayList<ElementDescriptor> children = new ArrayList<ElementDescriptor>(); - for (Entry<String, DeclareStyleableInfo> entry : styleMap.entrySet()) { - DeclareStyleableInfo childStyle = entry.getValue(); - boolean isParent = false; - String[] parents = childStyle.getParents(); - if (parents != null) { - for (String parent: parents) { - if (styleName.equals(parent)) { - isParent = true; - break; - } - } - } - if (isParent) { - String childStyleName = entry.getKey(); - String childXmlName = guessXmlName(childStyleName); - - // create or re-use element - ElementDescriptor child = existingElementDescs.get(childXmlName); - if (child == null) { - child = createElement(childXmlName); - existingElementDescs.put(childXmlName, child); - } - children.add(child); - - inflateElement(styleMap, - overrides, - requiredAttributes, - existingElementDescs, - child, - childStyleName); - } - } - elemDesc.setChildren(children.toArray(new ElementDescriptor[children.size()])); - } - - /** - * Get an UI name from the element XML name. - * <p/> - * Capitalizes the first letter and replace non-alphabet by a space followed by a capital. - */ - private String getUiName(String xmlName) { - StringBuilder sb = new StringBuilder(); - - boolean capitalize = true; - for (char c : xmlName.toCharArray()) { - if (capitalize && c >= 'a' && c <= 'z') { - sb.append((char)(c + 'A' - 'a')); - capitalize = false; - } else if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { - sb.append(' '); - capitalize = true; - } else { - sb.append(c); - } - } - - return sb.toString(); - } - - /** - * Guesses the style name for a given XML element name. - * <p/> - * The rules are: - * - capitalize the first letter: - * - if there's a dash, skip it and capitalize the next one - * - prefix AndroidManifest - * The exception is "manifest" which just becomes AndroidManifest. - * <p/> - * Examples: - * - manifest => AndroidManifest - * - application => AndroidManifestApplication - * - uses-permission => AndroidManifestUsesPermission - */ - private String guessStyleName(String xmlName) { - StringBuilder sb = new StringBuilder(); - - if (!xmlName.equals(MANIFEST_NODE_NAME)) { - boolean capitalize = true; - for (char c : xmlName.toCharArray()) { - if (capitalize && c >= 'a' && c <= 'z') { - sb.append((char)(c + 'A' - 'a')); - capitalize = false; - } else if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { - // not a letter -- skip the character and capitalize the next one - capitalize = true; - } else { - sb.append(c); - } - } - } - - sb.insert(0, ANDROID_MANIFEST_STYLEABLE); - return sb.toString(); - } - - /** - * This method performs a sanity check to make sure all the styles declared in the - * manifestMap are actually defined in the actual element descriptors and reachable from - * the manifestElement root node. - */ - private void sanityCheck(Map<String, DeclareStyleableInfo> manifestMap, - ElementDescriptor manifestElement) { - TreeSet<String> elementsDeclared = new TreeSet<String>(); - findAllElementNames(manifestElement, elementsDeclared); - - TreeSet<String> stylesDeclared = new TreeSet<String>(); - for (String styleName : manifestMap.keySet()) { - if (styleName.startsWith(ANDROID_MANIFEST_STYLEABLE)) { - stylesDeclared.add(styleName); - } - } - - for (Iterator<String> it = elementsDeclared.iterator(); it.hasNext();) { - String xmlName = it.next(); - String styleName = guessStyleName(xmlName); - if (stylesDeclared.remove(styleName)) { - it.remove(); - } - } - - StringBuilder sb = new StringBuilder(); - if (!stylesDeclared.isEmpty()) { - sb.append("Warning, ADT/SDK Mismatch! The following elements are declared by the SDK but unknown to ADT: "); - for (String name : stylesDeclared) { - name = guessXmlName(name); - - if (name != stylesDeclared.last()) { - sb.append(", "); //$NON-NLS-1$ - } - } - - AdtPlugin.log(IStatus.WARNING, "%s", sb.toString()); - AdtPlugin.printToConsole((String)null, sb); - sb.setLength(0); - } - - if (!elementsDeclared.isEmpty()) { - sb.append("Warning, ADT/SDK Mismatch! The following elements are declared by ADT but not by the SDK: "); - for (String name : elementsDeclared) { - sb.append(name); - if (name != elementsDeclared.last()) { - sb.append(", "); //$NON-NLS-1$ - } - } - - AdtPlugin.log(IStatus.WARNING, "%s", sb.toString()); - AdtPlugin.printToConsole((String)null, sb); - } - } - - /** - * Performs an approximate translation of the style name into a potential - * xml name. This is more or less the reverse from guessStyleName(). - * - * @return The XML local name for a given style name. - */ - private String guessXmlName(String name) { - StringBuilder sb = new StringBuilder(); - if (ANDROID_MANIFEST_STYLEABLE.equals(name)) { - sb.append(MANIFEST_NODE_NAME); - } else { - name = name.replace(ANDROID_MANIFEST_STYLEABLE, ""); //$NON-NLS-1$ - boolean first_char = true; - for (char c : name.toCharArray()) { - if (c >= 'A' && c <= 'Z') { - if (!first_char) { - sb.append('-'); - } - c = (char) (c - 'A' + 'a'); - } - sb.append(c); - first_char = false; - } - } - return sb.toString(); - } - - /** - * Helper method used by {@link #sanityCheck(Map, ElementDescriptor)} to find all the - * {@link ElementDescriptor} names defined by the tree of descriptors. - * <p/> - * Note: this assumes no circular reference in the tree of {@link ElementDescriptor}s. - */ - private void findAllElementNames(ElementDescriptor element, TreeSet<String> declared) { - declared.add(element.getXmlName()); - for (ElementDescriptor desc : element.getChildren()) { - findAllElementNames(desc, declared); - } - } - - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java deleted file mode 100644 index eab7f09..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * Describes an 'Application' class XML attribute. It is displayed by a - * {@link UiClassAttributeNode}, that restricts creation and selection to classes - * inheriting from android.app.Application. - */ -public class ApplicationAttributeDescriptor extends TextAttributeDescriptor { - - public ApplicationAttributeDescriptor(String xmlLocalName, String uiName, - String nsUri, String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * @return A new {@link UiClassAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiClassAttributeNode("android.app.Application", //$NON-NLS-1$ - null /* postCreationAction */, false /* mandatory */, this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java deleted file mode 100644 index abaf438..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode.IPostTypeCreationAction; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * Describes an XML attribute representing a class name. - * It is displayed by a {@link UiClassAttributeNode}. - */ -public class ClassAttributeDescriptor extends TextAttributeDescriptor { - - /** Superclass of the class value. */ - private String mSuperClassName; - - private IPostTypeCreationAction mPostCreationAction; - - /** indicates if the class parameter is mandatory */ - boolean mMandatory; - - /** - * Creates a new {@link ClassAttributeDescriptor} - * @param superClassName the fully qualified name of the superclass of the class represented - * by the attribute. - * @param xmlLocalName The XML name of the attribute (case sensitive, with android: prefix). - * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param tooltip A non-empty tooltip string or null. - * @param mandatory indicates if the class attribute is mandatory. - */ - public ClassAttributeDescriptor(String superClassName, - String xmlLocalName, String uiName, String nsUri, - String tooltip, boolean mandatory) { - super(xmlLocalName, uiName, nsUri, tooltip); - mSuperClassName = superClassName; - } - - /** - * Creates a new {@link ClassAttributeDescriptor} - * @param superClassName the fully qualified name of the superclass of the class represented - * by the attribute. - * @param postCreationAction the {@link IPostTypeCreationAction} to be executed on the - * newly created class. - * @param xmlLocalName The XML local name of the attribute (case sensitive). - * @param uiName The UI name of the attribute. Cannot be an empty string and cannot be null. - * @param nsUri The URI of the attribute. Can be null if attribute has no namespace. - * See {@link SdkConstants#NS_RESOURCES} for a common value. - * @param tooltip A non-empty tooltip string or null. - * @param mandatory indicates if the class attribute is mandatory. - */ - public ClassAttributeDescriptor(String superClassName, - IPostTypeCreationAction postCreationAction, - String xmlLocalName, String uiName, String nsUri, - String tooltip, boolean mandatory) { - super(xmlLocalName, uiName, nsUri, tooltip); - mSuperClassName = superClassName; - mPostCreationAction = postCreationAction; - } - - /** - * @return A new {@link UiClassAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiClassAttributeNode(mSuperClassName, mPostCreationAction, - mMandatory, this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java deleted file mode 100644 index 6e589f7..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * Describes a 'Instrumentation' class XML attribute. It is displayed by a - * {@link UiClassAttributeNode}, that restricts creation and selection to classes inheriting from - * android.app.Instrumentation. - */ -public class InstrumentationAttributeDescriptor extends TextAttributeDescriptor { - - public InstrumentationAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * @return A new {@link UiClassAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiClassAttributeNode(AndroidConstants.CLASS_INSTRUMENTATION, - null /* postCreationAction */, true /* mandatory */, this, uiParent); - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ManifestElementDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ManifestElementDescriptor.java deleted file mode 100644 index d89292b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ManifestElementDescriptor.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.model.UiManifestElementNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * {@link ManifestElementDescriptor} describes an XML element node, with its - * element name, its possible attributes, its possible child elements but also - * its display name and tooltip. - * - * This {@link ElementDescriptor} is specialized to create {@link UiManifestElementNode} UI nodes. - */ -public class ManifestElementDescriptor extends ElementDescriptor { - - /** - * Constructs a new {@link ManifestElementDescriptor}. - * - * @param xml_name The XML element node name. Case sensitive. - * @param ui_name The XML element name for the user interface, typically capitalized. - * @param tooltip An optional tooltip. Can be null or empty. - * @param sdk_url An optional SKD URL. Can be null or empty. - * @param attributes The list of allowed attributes. Can be null or empty. - * @param children The list of allowed children. Can be null or empty. - * @param mandatory Whether this node must always exist (even for empty models). - */ - public ManifestElementDescriptor(String xml_name, String ui_name, String tooltip, String sdk_url, - AttributeDescriptor[] attributes, - ElementDescriptor[] children, - boolean mandatory) { - super(xml_name, ui_name, tooltip, sdk_url, attributes, children, mandatory); - } - - /** - * Constructs a new {@link ManifestElementDescriptor}. - * - * @param xml_name The XML element node name. Case sensitive. - * @param ui_name The XML element name for the user interface, typically capitalized. - * @param tooltip An optional tooltip. Can be null or empty. - * @param sdk_url An optional SKD URL. Can be null or empty. - * @param attributes The list of allowed attributes. Can be null or empty. - * @param children The list of allowed children. Can be null or empty. - */ - public ManifestElementDescriptor(String xml_name, String ui_name, String tooltip, String sdk_url, - AttributeDescriptor[] attributes, - ElementDescriptor[] children) { - super(xml_name, ui_name, tooltip, sdk_url, attributes, children, false); - } - - /** - * This is a shortcut for - * ManifestElementDescriptor(xml_name, xml_name.capitalize(), null, null, null, children). - * This constructor is mostly used for unit tests. - * - * @param xml_name The XML element node name. Case sensitive. - */ - public ManifestElementDescriptor(String xml_name, ElementDescriptor[] children) { - super(xml_name, children); - } - - /** - * This is a shortcut for - * ManifestElementDescriptor(xml_name, xml_name.capitalize(), null, null, null, null). - * This constructor is mostly used for unit tests. - * - * @param xml_name The XML element node name. Case sensitive. - */ - public ManifestElementDescriptor(String xml_name) { - super(xml_name, null); - } - - /** - * @return A new {@link UiElementNode} linked to this descriptor. - */ - @Override - public UiElementNode createUiNode() { - return new UiManifestElementNode(this); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PackageAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PackageAttributeDescriptor.java deleted file mode 100644 index 34c5d0d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PackageAttributeDescriptor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.model.UiPackageAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * Describes a package XML attribute. It is displayed by a {@link UiPackageAttributeNode}. - */ -public class PackageAttributeDescriptor extends TextAttributeDescriptor { - - public PackageAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * @return A new {@link UiPackageAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiPackageAttributeNode(this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PostActivityCreationAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PostActivityCreationAction.java deleted file mode 100644 index 3442c24..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PostActivityCreationAction.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode.IPostTypeCreationAction; - -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; - -/** - * Action to be executed after an Activity class is created. - */ -class PostActivityCreationAction implements IPostTypeCreationAction { - - private final static PostActivityCreationAction sAction = new PostActivityCreationAction(); - - private PostActivityCreationAction() { - // private constructor to enforce singleton. - } - - - /** - * Returns the action. - */ - public static IPostTypeCreationAction getAction() { - return sAction; - } - - /** - * Processes a newly created Activity. - * - */ - public void processNewType(IType newType) { - try { - String methodContent = - " /** Called when the activity is first created. */\n" + - " @Override\n" + - " public void onCreate(Bundle savedInstanceState) {\n" + - " super.onCreate(savedInstanceState);\n" + - "\n" + - " // TODO Auto-generated method stub\n" + - " }"; - newType.createMethod(methodContent, null /* sibling*/, false /* force */, - new NullProgressMonitor()); - - // we need to add the import for Bundle, so we need the compilation unit. - // Since the type could be enclosed in other types, we loop till we find it. - ICompilationUnit compilationUnit = null; - IJavaElement element = newType; - do { - IJavaElement parentElement = element.getParent(); - if (parentElement != null) { - if (parentElement.getElementType() == IJavaElement.COMPILATION_UNIT) { - compilationUnit = (ICompilationUnit)parentElement; - } - - element = parentElement; - } else { - break; - } - } while (compilationUnit == null); - - if (compilationUnit != null) { - compilationUnit.createImport(AndroidConstants.CLASS_BUNDLE, - null /* sibling */, new NullProgressMonitor()); - } - } catch (JavaModelException e) { - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PostReceiverCreationAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PostReceiverCreationAction.java deleted file mode 100644 index 5a8137d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/PostReceiverCreationAction.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode.IPostTypeCreationAction; - -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; - -/** - * Action to be executed after an BroadcastReceiver class is created. - */ -class PostReceiverCreationAction implements IPostTypeCreationAction { - - private final static PostReceiverCreationAction sAction = new PostReceiverCreationAction(); - - private PostReceiverCreationAction() { - // private constructor to enforce singleton. - } - - /** - * Returns the action. - */ - public static IPostTypeCreationAction getAction() { - return sAction; - } - - /** - * Processes a newly created Activity. - * - */ - public void processNewType(IType newType) { - try { - String methodContent = - " @Override\n" + - " public void onReceive(Context context, Intent intent) {\n" + - " // TODO Auto-generated method stub\n" + - " }"; - newType.createMethod(methodContent, null /* sibling*/, false /* force */, - new NullProgressMonitor()); - - // we need to add the import for Bundle, so we need the compilation unit. - // Since the type could be enclosed in other types, we loop till we find it. - ICompilationUnit compilationUnit = null; - IJavaElement element = newType; - do { - IJavaElement parentElement = element.getParent(); - if (parentElement != null) { - if (parentElement.getElementType() == IJavaElement.COMPILATION_UNIT) { - compilationUnit = (ICompilationUnit)parentElement; - } - - element = parentElement; - } else { - break; - } - } while (compilationUnit == null); - - if (compilationUnit != null) { - compilationUnit.createImport(AndroidConstants.CLASS_CONTEXT, - null /* sibling */, new NullProgressMonitor()); - compilationUnit.createImport(AndroidConstants.CLASS_INTENT, - null /* sibling */, new NullProgressMonitor()); - } - } catch (JavaModelException e) { - // looks like the class already existed (this happens when the user check to create - // inherited abstract methods). - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ThemeAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ThemeAttributeDescriptor.java deleted file mode 100644 index 4219007..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ThemeAttributeDescriptor.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.descriptors; - -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiResourceAttributeNode; - -/** - * Describes a Theme/Style XML attribute displayed by a {@link UiResourceAttributeNode} - */ -public final class ThemeAttributeDescriptor extends TextAttributeDescriptor { - - public ThemeAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * @return A new {@link UiResourceAttributeNode} linked to this theme descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiResourceAttributeNode(ResourceType.STYLE, this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java deleted file mode 100644 index f8aac1d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.model; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.ide.eclipse.common.project.BaseProjectHelper; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiTextAttributeNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.ITypeHierarchy; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.search.IJavaSearchScope; -import org.eclipse.jdt.core.search.SearchEngine; -import org.eclipse.jdt.ui.IJavaElementSearchConstants; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction; -import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension; -import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor; -import org.eclipse.jdt.ui.dialogs.ITypeSelectionComponent; -import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension; -import org.eclipse.jdt.ui.wizards.NewClassWizardPage; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.dialogs.SelectionDialog; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.w3c.dom.Element; - -import java.util.ArrayList; - -/** - * Represents an XML attribute for a class, that can be modified using a simple text field or - * a dialog to choose an existing class. Also, there's a link to create a new class. - * <p/> - * See {@link UiTextAttributeNode} for more information. - */ -public class UiClassAttributeNode extends UiTextAttributeNode { - - private String mReferenceClass; - private IPostTypeCreationAction mPostCreationAction; - private boolean mMandatory; - - private class HierarchyTypeSelection extends TypeSelectionExtension { - - private IJavaProject mJavaProject; - - public HierarchyTypeSelection(IProject project, String referenceClass) { - mJavaProject = JavaCore.create(project); - mReferenceClass = referenceClass; - } - - @Override - public ITypeInfoFilterExtension getFilterExtension() { - return new ITypeInfoFilterExtension() { - public boolean select(ITypeInfoRequestor typeInfoRequestor) { - String packageName = typeInfoRequestor.getPackageName(); - String typeName = typeInfoRequestor.getTypeName(); - String enclosingType = typeInfoRequestor.getEnclosingName(); - - // build the full class name. - StringBuilder sb = new StringBuilder(packageName); - sb.append('.'); - if (enclosingType.length() > 0) { - sb.append(enclosingType); - sb.append('.'); - } - sb.append(typeName); - - String className = sb.toString(); - - try { - IType type = mJavaProject.findType(className); - if (type != null) { - // get the type hierarchy - ITypeHierarchy hierarchy = type.newSupertypeHierarchy( - new NullProgressMonitor()); - - // if the super class is not the reference class, it may inherit from - // it so we get its supertype. At some point it will be null and we - // will return false; - IType superType = type; - while ((superType = hierarchy.getSuperclass(superType)) != null) { - if (mReferenceClass.equals(superType.getFullyQualifiedName())) { - return true; - } - } - } - } catch (JavaModelException e) { - } - - return false; - } - }; - } - } - - /** - * Classes which implement this interface provide a method processing newly created classes. - */ - public static interface IPostTypeCreationAction { - /** - * Sent to process a newly created class. - * @param newType the IType representing the newly created class. - */ - public void processNewType(IType newType); - } - - /** - * Creates a {@link UiClassAttributeNode} object that will display ui to select or create - * classes. - * @param referenceClass The allowed supertype of the classes that are to be selected - * or created. Can be null. - * @param postCreationAction a {@link IPostTypeCreationAction} object handling post creation - * modification of the class. - * @param mandatory indicates if the class value is mandatory - * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node. - */ - public UiClassAttributeNode(String referenceClass, IPostTypeCreationAction postCreationAction, - boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - - mReferenceClass = referenceClass; - mPostCreationAction = postCreationAction; - mMandatory = mandatory; - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public void createUiControl(final Composite parent, IManagedForm managedForm) { - setManagedForm(managedForm); - FormToolkit toolkit = managedForm.getToolkit(); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - - StringBuilder label = new StringBuilder(); - label.append("<form><p><a href='unused'>"); - label.append(desc.getUiName()); - label.append("</a></p></form>"); - FormText formText = SectionHelper.createFormText(parent, toolkit, true /* isHtml */, - label.toString(), true /* setupLayoutData */); - formText.addHyperlinkListener(new HyperlinkAdapter() { - @Override - public void linkActivated(HyperlinkEvent e) { - super.linkActivated(e); - handleLabelClick(); - } - }); - formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - SectionHelper.addControlTooltip(formText, desc.getTooltip()); - - Composite composite = toolkit.createComposite(parent); - composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); - GridLayout gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - composite.setLayout(gl); - // Fixes missing text borders under GTK... also requires adding a 1-pixel margin - // for the text field below - toolkit.paintBordersFor(composite); - - final Text text = toolkit.createText(composite, getCurrentValue()); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK - text.setLayoutData(gd); - Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); - - setTextWidget(text); - - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - handleBrowseClick(); - } - }); - } - - /* (non-java doc) - * - * Add a modify listener that will check the validity of the class - */ - @Override - protected void onAddValidators(final Text text) { - ModifyListener listener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - try { - String textValue = text.getText().trim(); - if (textValue.length() == 0) { - if (mMandatory) { - setErrorMessage("Value is mandatory", text); - } else { - setErrorMessage(null, text); - } - return; - } - // first we need the current java package. - String javaPackage = getManifestPackage(); - - // build the fully qualified name of the class - String className = AndroidManifestHelper.combinePackageAndClassName(javaPackage, - textValue); - - // only test the vilibility for activities. - boolean testVisibility = AndroidConstants.CLASS_ACTIVITY.equals( - mReferenceClass); - - // test the class - setErrorMessage(BaseProjectHelper.testClassForManifest( - BaseProjectHelper.getJavaProject(getProject()), className, - mReferenceClass, testVisibility), text); - } catch (CoreException ce) { - setErrorMessage(ce.getMessage(), text); - } - } - }; - - text.addModifyListener(listener); - - // Make sure the validator removes its message(s) when the widget is disposed - text.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - // we don't want to use setErrorMessage, because we don't want to reset - // the error flag in the UiAttributeNode - getManagedForm().getMessageManager().removeMessage(text, text); - } - }); - - // Finally call the validator once to make sure the initial value is processed - listener.modifyText(null); - } - - private void handleBrowseClick() { - Text text = getTextWidget(); - - // we need to get the project of the manifest. - IProject project = getProject(); - if (project != null) { - - // Create a search scope including only the source folder of the current - // project. - IJavaSearchScope scope = SearchEngine.createJavaSearchScope( - getPackageFragmentRoots(project), false); - - try { - SelectionDialog dlg = JavaUI.createTypeDialog(text.getShell(), - PlatformUI.getWorkbench().getProgressService(), - scope, - IJavaElementSearchConstants.CONSIDER_CLASSES, // style - false, // no multiple selection - "**", //$NON-NLS-1$ //filter - new HierarchyTypeSelection(project, mReferenceClass)); - dlg.setMessage(String.format("Select class name for element %1$s:", - getUiParent().getBreadcrumbTrailDescription(false /* include_root */))); - if (dlg instanceof ITypeSelectionComponent) { - ((ITypeSelectionComponent)dlg).triggerSearch(); - } - - if (dlg.open() == Window.OK) { - Object[] results = dlg.getResult(); - if (results.length == 1) { - handleNewType((IType)results[0]); - } - } - } catch (JavaModelException e1) { - } - } - } - - private void handleLabelClick() { - // get the current value - String className = getTextWidget().getText().trim(); - - // get the package name from the manifest. - String packageName = getManifestPackage(); - - if (className.length() == 0) { - createNewClass(packageName, null /* className */); - } else { - // build back the fully qualified class name. - String fullClassName = className; - if (className.startsWith(".")) { //$NON-NLS-1$ - fullClassName = packageName + className; - } else { - String[] segments = className.split(AndroidConstants.RE_DOT); - if (segments.length == 1) { - fullClassName = packageName + "." + className; //$NON-NLS-1$ - } - } - - // in case the type is enclosed, we need to replace the $ with . - fullClassName = fullClassName.replaceAll("\\$", "\\."); //$NON-NLS-1$ //$NON-NLS2$ - - // now we try to find the file that contains this class and we open it in the editor. - IProject project = getProject(); - IJavaProject javaProject = JavaCore.create(project); - - try { - IType result = javaProject.findType(fullClassName); - if (result != null) { - JavaUI.openInEditor(result); - } else { - // split the last segment from the fullClassname - int index = fullClassName.lastIndexOf('.'); - if (index != -1) { - createNewClass(fullClassName.substring(0, index), - fullClassName.substring(index+1)); - } else { - createNewClass(packageName, className); - } - } - } catch (JavaModelException e) { - } catch (PartInitException e) { - } - } - } - - private IProject getProject() { - UiElementNode uiNode = getUiParent(); - AndroidEditor editor = uiNode.getEditor(); - IEditorInput input = editor.getEditorInput(); - if (input instanceof IFileEditorInput) { - // from the file editor we can get the IFile object, and from it, the IProject. - IFile file = ((IFileEditorInput)input).getFile(); - return file.getProject(); - } - - return null; - } - - - /** - * Returns the current value of the /manifest/package attribute. - * @return the package or an empty string if not found - */ - private String getManifestPackage() { - // get the root uiNode to get the 'package' attribute value. - UiElementNode rootNode = getUiParent().getUiRoot(); - - Element xmlElement = (Element) rootNode.getXmlNode(); - - if (xmlElement != null) { - return xmlElement.getAttribute(AndroidManifestDescriptors.PACKAGE_ATTR); - } - return ""; //$NON-NLS-1$ - } - - - /** - * Computes and return the {@link IPackageFragmentRoot}s corresponding to the source folders of - * the specified project. - * @param project the project - * @return an array of IPackageFragmentRoot. - */ - private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project) { - ArrayList<IPackageFragmentRoot> result = new ArrayList<IPackageFragmentRoot>(); - try { - IJavaProject javaProject = JavaCore.create(project); - IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); - for (int i = 0; i < roots.length; i++) { - IClasspathEntry entry = roots[i].getRawClasspathEntry(); - if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { - result.add(roots[i]); - } - } - } catch (JavaModelException e) { - } - - return result.toArray(new IPackageFragmentRoot[result.size()]); - } - - private void handleNewType(IType type) { - Text text = getTextWidget(); - - // get the fully qualified name with $ to properly detect the enclosing types. - String name = type.getFullyQualifiedName('$'); - - String packageValue = getManifestPackage(); - - // check if the class doesn't start with the package. - if (packageValue.length() > 0 && name.startsWith(packageValue)) { - // if it does, we remove the package and the first dot. - name = name.substring(packageValue.length() + 1); - - // look for how many segments we have left. - // if one, just write it that way. - // if more than one, write it with a leading dot. - String[] packages = name.split(AndroidConstants.RE_DOT); - if (packages.length == 1) { - text.setText(name); - } else { - text.setText("." + name); //$NON-NLS-1$ - } - } else { - text.setText(name); - } - } - - private void createNewClass(String packageName, String className) { - // create the wizard page for the class creation, and configure it - NewClassWizardPage page = new NewClassWizardPage(); - - // set the parent class - page.setSuperClass(mReferenceClass, true /* canBeModified */); - - // get the source folders as java elements. - IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject()); - - IPackageFragmentRoot currentRoot = null; - IPackageFragment currentFragment = null; - int packageMatchCount = -1; - - for (IPackageFragmentRoot root : roots) { - // Get the java element for the package. - // This method is said to always return a IPackageFragment even if the - // underlying folder doesn't exist... - IPackageFragment fragment = root.getPackageFragment(packageName); - if (fragment != null && fragment.exists()) { - // we have a perfect match! we use it. - currentRoot = root; - currentFragment = fragment; - packageMatchCount = -1; - break; - } else { - // we don't have a match. we look for the fragment with the best match - // (ie the closest parent package we can find) - try { - IJavaElement[] children; - children = root.getChildren(); - for (IJavaElement child : children) { - if (child instanceof IPackageFragment) { - fragment = (IPackageFragment)child; - if (packageName.startsWith(fragment.getElementName())) { - // its a match. get the number of segments - String[] segments = fragment.getElementName().split("\\."); //$NON-NLS-1$ - if (segments.length > packageMatchCount) { - packageMatchCount = segments.length; - currentFragment = fragment; - currentRoot = root; - } - } - } - } - } catch (JavaModelException e) { - // Couldn't get the children: we just ignore this package root. - } - } - } - - ArrayList<IPackageFragment> createdFragments = null; - - if (currentRoot != null) { - // if we have a perfect match, we set it and we're done. - if (packageMatchCount == -1) { - page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/); - page.setPackageFragment(currentFragment, true /* canBeModified */); - } else { - // we have a partial match. - // create the package. We have to start with the first segment so that we - // know what to delete in case of a cancel. - try { - createdFragments = new ArrayList<IPackageFragment>(); - - int totalCount = packageName.split("\\.").length; //$NON-NLS-1$ - int count = 0; - int index = -1; - // skip the matching packages - while (count < packageMatchCount) { - index = packageName.indexOf('.', index+1); - count++; - } - - // create the rest of the segments, except for the last one as indexOf will - // return -1; - while (count < totalCount - 1) { - index = packageName.indexOf('.', index+1); - count++; - createdFragments.add(currentRoot.createPackageFragment( - packageName.substring(0, index), - true /* force*/, new NullProgressMonitor())); - } - - // create the last package - createdFragments.add(currentRoot.createPackageFragment( - packageName, true /* force*/, new NullProgressMonitor())); - - // set the root and fragment in the Wizard page - page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/); - page.setPackageFragment(createdFragments.get(createdFragments.size()-1), - true /* canBeModified */); - } catch (JavaModelException e) { - // if we can't create the packages, there's a problem. we revert to the default - // package - for (IPackageFragmentRoot root : roots) { - // Get the java element for the package. - // This method is said to always return a IPackageFragment even if the - // underlying folder doesn't exist... - IPackageFragment fragment = root.getPackageFragment(packageName); - if (fragment != null && fragment.exists()) { - page.setPackageFragmentRoot(root, true /* canBeModified*/); - page.setPackageFragment(fragment, true /* canBeModified */); - break; - } - } - } - } - } else if (roots.length > 0) { - // if we haven't found a valid fragment, we set the root to the first source folder. - page.setPackageFragmentRoot(roots[0], true /* canBeModified*/); - } - - // if we have a starting class name we use it - if (className != null) { - page.setTypeName(className, true /* canBeModified*/); - } - - // create the action that will open it the wizard. - OpenNewClassWizardAction action = new OpenNewClassWizardAction(); - action.setConfiguredWizardPage(page); - action.run(); - IJavaElement element = action.getCreatedElement(); - - if (element != null) { - if (element.getElementType() == IJavaElement.TYPE) { - - IType type = (IType)element; - - if (mPostCreationAction != null) { - mPostCreationAction.processNewType(type); - } - - handleNewType(type); - } - } else { - // lets delete the packages we created just for this. - // we need to start with the leaf and go up - if (createdFragments != null) { - try { - for (int i = createdFragments.size() - 1 ; i >= 0 ; i--) { - createdFragments.get(i).delete(true /* force*/, new NullProgressMonitor()); - } - } catch (JavaModelException e) { - e.printStackTrace(); - } - } - } - } - - /** - * Sets the error messages. If message is <code>null</code>, the message is removed. - * @param message the message to set, or <code>null</code> to remove the current message - * @param textWidget the {@link Text} widget associated to the message. - */ - private final void setErrorMessage(String message, Text textWidget) { - if (message != null) { - setHasError(true); - getManagedForm().getMessageManager().addMessage(textWidget, message, null /* data */, - IMessageProvider.ERROR, textWidget); - } else { - setHasError(false); - getManagedForm().getMessageManager().removeMessage(textWidget, textWidget); - } - } - - @Override - public String[] getPossibleValues() { - // TODO: compute a list of existing classes for content assist completion - return null; - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java deleted file mode 100644 index fb8f211..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiManifestElementNode.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.model; - -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.manifest.descriptors.ManifestElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.sdklib.SdkConstants; - -import org.w3c.dom.Element; - -/** - * Represents an XML node that can be modified by the user interface in the XML editor. - * <p/> - * Each tree viewer used in the application page's parts needs to keep a model representing - * each underlying node in the tree. This interface represents the base type for such a node. - * <p/> - * Each node acts as an intermediary model between the actual XML model (the real data support) - * and the tree viewers or the corresponding page parts. - * <p/> - * Element nodes don't contain data per se. Their data is contained in their attributes - * as well as their children's attributes, see {@link UiAttributeNode}. - * <p/> - * The structure of a given {@link UiElementNode} is declared by a corresponding - * {@link ElementDescriptor}. - */ -public final class UiManifestElementNode extends UiElementNode { - - /** - * Creates a new {@link UiElementNode} described by a given {@link ElementDescriptor}. - * - * @param elementDescriptor The {@link ElementDescriptor} for the XML node. Cannot be null. - */ - public UiManifestElementNode(ManifestElementDescriptor elementDescriptor) { - super(elementDescriptor); - } - - /** - * Computes a short string describing the UI node suitable for tree views. - * Uses the element's attribute "android:name" if present, or the "android:label" one - * followed by the element's name. - * - * @return A short string describing the UI node suitable for tree views. - */ - @Override - public String getShortDescription() { - if (getXmlNode() != null && - getXmlNode() instanceof Element && - getXmlNode().hasAttributes()) { - - AndroidManifestDescriptors manifestDescriptors = - getAndroidTarget().getManifestDescriptors(); - - // Application and Manifest nodes have a special treatment: they are unique nodes - // so we don't bother trying to differentiate their strings and we fall back to - // just using the UI name below. - ElementDescriptor desc = getDescriptor(); - if (desc != manifestDescriptors.getManifestElement() && - desc != manifestDescriptors.getApplicationElement()) { - Element elem = (Element) getXmlNode(); - String attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, - AndroidManifestDescriptors.ANDROID_NAME_ATTR); - if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, - AndroidManifestDescriptors.ANDROID_LABEL_ATTR); - } - if (attr != null && attr.length() > 0) { - return String.format("%1$s (%2$s)", attr, getDescriptor().getUiName()); - } - } - } - - return String.format("%1$s", getDescriptor().getUiName()); - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiPackageAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiPackageAttributeNode.java deleted file mode 100644 index 02fb44f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiPackageAttributeNode.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.model; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiTextAttributeNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IPackageFragment; -import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jdt.ui.actions.OpenNewPackageWizardAction; -import org.eclipse.jdt.ui.actions.ShowInPackageViewAction; -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.IWorkbenchPartSite; -import org.eclipse.ui.dialogs.SelectionDialog; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; - -import java.util.ArrayList; - -/** - * Represents an XML attribute for a package, that can be modified using a simple text field or - * a dialog to choose an existing package. Also, there's a link to create a new package. - * <p/> - * See {@link UiTextAttributeNode} for more information. - */ -public class UiPackageAttributeNode extends UiTextAttributeNode { - - /** - * Creates a {@link UiPackageAttributeNode} object that will display ui to select or create - * a package. - * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node. - */ - public UiPackageAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public void createUiControl(final Composite parent, final IManagedForm managedForm) { - setManagedForm(managedForm); - FormToolkit toolkit = managedForm.getToolkit(); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - - StringBuilder label = new StringBuilder(); - label.append("<form><p><a href='unused'>"); //$NON-NLS-1$ - label.append(desc.getUiName()); - label.append("</a></p></form>"); //$NON-NLS-1$ - FormText formText = SectionHelper.createFormText(parent, toolkit, true /* isHtml */, - label.toString(), true /* setupLayoutData */); - formText.addHyperlinkListener(new HyperlinkAdapter() { - @Override - public void linkActivated(HyperlinkEvent e) { - super.linkActivated(e); - doLabelClick(); - } - }); - formText.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - SectionHelper.addControlTooltip(formText, desc.getTooltip()); - - Composite composite = toolkit.createComposite(parent); - composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); - GridLayout gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - composite.setLayout(gl); - // Fixes missing text borders under GTK... also requires adding a 1-pixel margin - // for the text field below - toolkit.paintBordersFor(composite); - - final Text text = toolkit.createText(composite, getCurrentValue()); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK - text.setLayoutData(gd); - - setTextWidget(text); - - Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); - - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - doBrowseClick(); - } - }); - - } - - /* (non-java doc) - * Adds a validator to the text field that calls managedForm.getMessageManager(). - */ - @Override - protected void onAddValidators(final Text text) { - ModifyListener listener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - String package_name = text.getText(); - if (package_name.indexOf('.') < 1) { - getManagedForm().getMessageManager().addMessage(text, - "Package name should contain at least two identifiers.", - null /* data */, IMessageProvider.ERROR, text); - } else { - getManagedForm().getMessageManager().removeMessage(text, text); - } - } - }; - - text.addModifyListener(listener); - - // Make sure the validator removes its message(s) when the widget is disposed - text.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - getManagedForm().getMessageManager().removeMessage(text, text); - } - }); - - // Finally call the validator once to make sure the initial value is processed - listener.modifyText(null); - } - - /** - * Handles response to the Browse button by creating a Package dialog. - * */ - private void doBrowseClick() { - Text text = getTextWidget(); - - // we need to get the project of the manifest. - IProject project = getProject(); - if (project != null) { - - try { - SelectionDialog dlg = JavaUI.createPackageDialog(text.getShell(), - JavaCore.create(project), 0); - dlg.setTitle("Select Android Package"); - dlg.setMessage("Select the package for the Android project."); - SelectionDialog.setDefaultImage(AdtPlugin.getAndroidLogo()); - - if (dlg.open() == Window.OK) { - Object[] results = dlg.getResult(); - if (results.length == 1) { - setPackageTextField((IPackageFragment)results[0]); - } - } - } catch (JavaModelException e1) { - } - } - } - - /** - * Handles response to the Label hyper link being activated. - */ - private void doLabelClick() { - // get the current package name - String package_name = getTextWidget().getText().trim(); - - if (package_name.length() == 0) { - createNewPackage(); - } else { - // Try to select the package in the Package Explorer for the current - // project and the current editor's site. - - IProject project = getProject(); - if (project == null) { - AdtPlugin.log(IStatus.ERROR, "Failed to get project for UiPackageAttribute"); //$NON-NLS-1$ - return; - } - - IWorkbenchPartSite site = getUiParent().getEditor().getSite(); - if (site == null) { - AdtPlugin.log(IStatus.ERROR, "Failed to get editor site for UiPackageAttribute"); //$NON-NLS-1$ - return; - } - - for (IPackageFragmentRoot root : getPackageFragmentRoots(project)) { - IPackageFragment fragment = root.getPackageFragment(package_name); - if (fragment != null && fragment.exists()) { - ShowInPackageViewAction action = new ShowInPackageViewAction(site); - action.run(fragment); - // This action's run() doesn't provide the status (although internally it could) - // so we just assume it worked. - return; - } - } - } - } - - /** - * Utility method that returns the project for the current file being edited. - * - * @return The IProject for the current file being edited or null. - */ - private IProject getProject() { - UiElementNode uiNode = getUiParent(); - AndroidEditor editor = uiNode.getEditor(); - IEditorInput input = editor.getEditorInput(); - if (input instanceof IFileEditorInput) { - // from the file editor we can get the IFile object, and from it, the IProject. - IFile file = ((IFileEditorInput)input).getFile(); - return file.getProject(); - } - - return null; - } - - /** - * Utility method that computes and returns the list of {@link IPackageFragmentRoot} - * corresponding to the source folder of the specified project. - * - * @param project the project - * @return an array of IPackageFragmentRoot. Can be empty but not null. - */ - private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project) { - ArrayList<IPackageFragmentRoot> result = new ArrayList<IPackageFragmentRoot>(); - try { - IJavaProject javaProject = JavaCore.create(project); - IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); - for (int i = 0; i < roots.length; i++) { - IClasspathEntry entry = roots[i].getRawClasspathEntry(); - if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { - result.add(roots[i]); - } - } - } catch (JavaModelException e) { - } - - return result.toArray(new IPackageFragmentRoot[result.size()]); - } - - /** - * Utility method that sets the package's text field to the package fragment's name. - * */ - private void setPackageTextField(IPackageFragment type) { - Text text = getTextWidget(); - - String name = type.getElementName(); - - text.setText(name); - } - - - /** - * Displays and handles a "Create Package Wizard". - * - * This is invoked by doLabelClick() when clicking on the hyperlink label with an - * empty package text field. - */ - private void createNewPackage() { - OpenNewPackageWizardAction action = new OpenNewPackageWizardAction(); - - IProject project = getProject(); - action.setSelection(new StructuredSelection(project)); - action.run(); - - IJavaElement element = action.getCreatedElement(); - if (element != null && - element.exists() && - element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { - setPackageTextField((IPackageFragment) element); - } - } - - @Override - public String[] getPossibleValues() { - // TODO: compute a list of existing packages for content assist completion - return null; - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationAttributesPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationAttributesPart.java deleted file mode 100644 index 01b0f8f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationAttributesPart.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.ui.UiElementPart; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; - -/** - * Application's attributes section part for Application page. - * <p/> - * This part is displayed at the top of the application page and displays all the possible - * attributes of an application node in the AndroidManifest (icon, class name, label, etc.) - */ -final class ApplicationAttributesPart extends UiElementPart { - - /** Listen to changes to the UI node for <application> and updates the UI */ - private AppNodeUpdateListener mAppNodeUpdateListener; - /** ManagedForm needed to create the UI controls */ - private IManagedForm mManagedForm; - - public ApplicationAttributesPart(Composite body, FormToolkit toolkit, ManifestEditor editor, - UiElementNode applicationUiNode) { - super(body, toolkit, editor, applicationUiNode, - "Application Attributes", // section title - "Defines the attributes specific to the application.", // section description - Section.TWISTIE | Section.EXPANDED); - } - - /** - * Changes and refreshes the Application UI node handle by the this part. - */ - @Override - public void setUiElementNode(UiElementNode uiElementNode) { - super.setUiElementNode(uiElementNode); - - createUiAttributes(mManagedForm); - } - - /* (non-java doc) - * Create the controls to edit the attributes for the given ElementDescriptor. - * <p/> - * This MUST not be called by the constructor. Instead it must be called from - * <code>initialize</code> (i.e. right after the form part is added to the managed form.) - * <p/> - * Derived classes can override this if necessary. - * - * @param managedForm The owner managed form - */ - @Override - protected void createFormControls(final IManagedForm managedForm) { - mManagedForm = managedForm; - setTable(createTableLayout(managedForm.getToolkit(), 4 /* numColumns */)); - - mAppNodeUpdateListener = new AppNodeUpdateListener(); - getUiElementNode().addUpdateListener(mAppNodeUpdateListener); - - createUiAttributes(mManagedForm); - } - - @Override - public void dispose() { - super.dispose(); - if (getUiElementNode() != null && mAppNodeUpdateListener != null) { - getUiElementNode().removeUpdateListener(mAppNodeUpdateListener); - mAppNodeUpdateListener = null; - } - } - - @Override - protected void createUiAttributes(IManagedForm managedForm) { - Composite table = getTable(); - if (table == null || managedForm == null) { - return; - } - - // Remove any old UI controls - for (Control c : table.getChildren()) { - c.dispose(); - } - - UiElementNode uiElementNode = getUiElementNode(); - AttributeDescriptor[] attr_desc_list = uiElementNode.getAttributeDescriptors(); - - // Display the attributes in 2 columns: - // attr 0 | attr 4 - // attr 1 | attr 5 - // attr 2 | attr 6 - // attr 3 | attr 7 - // that is we have to fill the grid in order 0, 4, 1, 5, 2, 6, 3, 7 - // thus index = i/2 + (i is odd * n/2) - int n = attr_desc_list.length; - int n2 = (int) Math.ceil(n / 2.0); - for (int i = 0; i < n; i++) { - AttributeDescriptor attr_desc = attr_desc_list[i / 2 + (i & 1) * n2]; - if (attr_desc instanceof XmlnsAttributeDescriptor) { - // Do not show hidden attributes - continue; - } - - UiAttributeNode ui_attr = uiElementNode.findUiAttribute(attr_desc); - if (ui_attr != null) { - ui_attr.createUiControl(table, managedForm); - } else { - // The XML has an extra attribute which wasn't declared in - // AndroidManifestDescriptors. This is not a problem, we just ignore it. - AdtPlugin.log(IStatus.WARNING, - "Attribute %1$s not declared in node %2$s, ignored.", //$NON-NLS-1$ - attr_desc.getXmlLocalName(), - uiElementNode.getDescriptor().getXmlName()); - } - } - - if (n == 0) { - createLabel(table, managedForm.getToolkit(), - "No attributes to display, waiting for SDK to finish loading...", - null /* tooltip */ ); - } - - // Initialize the enabled/disabled state - if (mAppNodeUpdateListener != null) { - mAppNodeUpdateListener.uiElementNodeUpdated(uiElementNode, null /* state, not used */); - } - - // Tell the section that the layout has changed. - layoutChanged(); - } - - /** - * This listener synchronizes the UI with the actual presence of the application XML node. - */ - private class AppNodeUpdateListener implements IUiUpdateListener { - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) { - // The UiElementNode for the application XML node always exists, even - // if there is no corresponding XML node in the XML file. - // - // We enable the UI here if the XML node is not null. - Composite table = getTable(); - boolean exists = (ui_node.getXmlNode() != null); - if (table != null && table.getEnabled() != exists) { - table.setEnabled(exists); - for (Control c : table.getChildren()) { - c.setEnabled(exists); - } - } - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationPage.java deleted file mode 100644 index 77527f0..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationPage.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ScrolledForm; - - -/** - * Page for "Application" settings, part of the AndroidManifest form editor. - * <p/> - * Useful reference: - * <a href="http://www.eclipse.org/articles/Article-Forms/article.html"> - * http://www.eclipse.org/articles/Article-Forms/article.html</a> - */ -public final class ApplicationPage extends FormPage { - /** Page id used for switching tabs programmatically */ - public final static String PAGE_ID = "application_page"; //$NON-NLS-1$ - - /** Container editor */ - ManifestEditor mEditor; - /** The Application Toogle part */ - private ApplicationToggle mTooglePart; - /** The Application Attributes part */ - private ApplicationAttributesPart mAttrPart; - /** The tree view block */ - private UiTreeBlock mTreeBlock; - - public ApplicationPage(ManifestEditor editor) { - super(editor, PAGE_ID, "Application"); // tab's label, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - form.setText("Android Manifest Application"); - form.setImage(AdtPlugin.getAndroidLogo()); - - UiElementNode appUiNode = getUiApplicationNode(); - - Composite body = form.getBody(); - FormToolkit toolkit = managedForm.getToolkit(); - - // We usually prefer to have a ColumnLayout here. However - // MasterDetailsBlock.createContent() below will reset the body's layout to a grid layout. - mTooglePart = new ApplicationToggle(body, toolkit, mEditor, appUiNode); - mTooglePart.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - managedForm.addPart(mTooglePart); - mAttrPart = new ApplicationAttributesPart(body, toolkit, mEditor, appUiNode); - mAttrPart.getSection().setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - managedForm.addPart(mAttrPart); - - mTreeBlock = new UiTreeBlock(mEditor, appUiNode, - false /* autoCreateRoot */, - null /* element filters */, - "Application Nodes", - "List of all elements in the application"); - mTreeBlock.createContent(managedForm); - } - - /** - * Retrieves the application UI node. Since this is a mandatory node, it *always* - * exists, even if there is no matching XML node. - */ - private UiElementNode getUiApplicationNode() { - AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors(); - if (manifestDescriptor != null) { - ElementDescriptor desc = manifestDescriptor.getApplicationElement(); - return mEditor.getUiRootNode().findUiChildNode(desc.getXmlName()); - } else { - // return the ui root node, as a dummy application root node. - return mEditor.getUiRootNode(); - } - } - - /** - * Changes and refreshes the Application UI node handled by the sub parts. - */ - public void refreshUiApplicationNode() { - UiElementNode appUiNode = getUiApplicationNode(); - if (mTooglePart != null) { - mTooglePart.setUiElementNode(appUiNode); - } - if (mAttrPart != null) { - mAttrPart.setUiElementNode(appUiNode); - } - if (mTreeBlock != null) { - mTreeBlock.changeRootAndDescriptors(appUiNode, - null /* element filters */, - true /* refresh */); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationToggle.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationToggle.java deleted file mode 100644 index 139575d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/ApplicationToggle.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.ui.UiElementPart; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener.UiUpdateState; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.Text; - -/** - * Appllication Toogle section part for application page. - */ -final class ApplicationToggle extends UiElementPart { - - /** Checkbox indicating whether an application node is present */ - private Button mCheckbox; - /** Listen to changes to the UI node for <application> and updates the checkbox */ - private AppNodeUpdateListener mAppNodeUpdateListener; - /** Internal flag to know where we're programmatically modifying the checkbox and we want to - * avoid triggering the checkbox's callback. */ - public boolean mInternalModification; - private FormText mTooltipFormText; - - public ApplicationToggle(Composite body, FormToolkit toolkit, ManifestEditor editor, - UiElementNode applicationUiNode) { - super(body, toolkit, editor, applicationUiNode, - "Application Toggle", - null, /* description */ - Section.TWISTIE | Section.EXPANDED); - } - - @Override - public void dispose() { - super.dispose(); - if (getUiElementNode() != null && mAppNodeUpdateListener != null) { - getUiElementNode().removeUpdateListener(mAppNodeUpdateListener); - mAppNodeUpdateListener = null; - } - } - - /** - * Changes and refreshes the Application UI node handle by the this part. - */ - @Override - public void setUiElementNode(UiElementNode uiElementNode) { - super.setUiElementNode(uiElementNode); - - updateTooltip(); - - // Set the state of the checkbox - mAppNodeUpdateListener.uiElementNodeUpdated(getUiElementNode(), - UiUpdateState.CHILDREN_CHANGED); - } - - /** - * Create the controls to edit the attributes for the given ElementDescriptor. - * <p/> - * This MUST not be called by the constructor. Instead it must be called from - * <code>initialize</code> (i.e. right after the form part is added to the managed form.) - * - * @param managedForm The owner managed form - */ - @Override - protected void createFormControls(IManagedForm managedForm) { - FormToolkit toolkit = managedForm.getToolkit(); - Composite table = createTableLayout(toolkit, 1 /* numColumns */); - - mTooltipFormText = createFormText(table, toolkit, true, "<form></form>", - false /* setupLayoutData */); - updateTooltip(); - - mCheckbox = toolkit.createButton(table, - "Define an <application> tag in the AndroidManifest.xml", - SWT.CHECK); - mCheckbox.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.TOP)); - mCheckbox.setSelection(false); - mCheckbox.addSelectionListener(new CheckboxSelectionListener()); - - mAppNodeUpdateListener = new AppNodeUpdateListener(); - getUiElementNode().addUpdateListener(mAppNodeUpdateListener); - - // Initialize the state of the checkbox - mAppNodeUpdateListener.uiElementNodeUpdated(getUiElementNode(), - UiUpdateState.CHILDREN_CHANGED); - - // Tell the section that the layout has changed. - layoutChanged(); - } - - /** - * Updates the application tooltip in the form text. - * If there is no tooltip, the form text is hidden. - */ - private void updateTooltip() { - boolean isVisible = false; - - String tooltip = getUiElementNode().getDescriptor().getTooltip(); - if (tooltip != null) { - tooltip = DescriptorsUtils.formatFormText(tooltip, - getUiElementNode().getDescriptor(), - Sdk.getCurrent().getDocumentationBaseUrl()); - - mTooltipFormText.setText(tooltip, true /* parseTags */, true /* expandURLs */); - mTooltipFormText.setImage(DescriptorsUtils.IMAGE_KEY, AdtPlugin.getAndroidLogo()); - mTooltipFormText.addHyperlinkListener(getEditor().createHyperlinkListener()); - isVisible = true; - } - - mTooltipFormText.setVisible(isVisible); - } - - /** - * This listener synchronizes the XML application node when the checkbox - * is changed by the user. - */ - private class CheckboxSelectionListener extends SelectionAdapter { - private Node mUndoXmlNode; - private Node mUndoXmlParent; - private Node mUndoXmlNextNode; - private Node mUndoXmlNextElement; - private Document mUndoXmlDocument; - - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - if (!mInternalModification && getUiElementNode() != null) { - getUiElementNode().getEditor().wrapUndoRecording( - mCheckbox.getSelection() - ? "Create or restore Application node" - : "Remove Application node", - new Runnable() { - public void run() { - getUiElementNode().getEditor().editXmlModel(new Runnable() { - public void run() { - if (mCheckbox.getSelection()) { - // The user wants an <application> node. - // Either restore a previous one - // or create a full new one. - boolean create = true; - if (mUndoXmlNode != null) { - create = !restoreApplicationNode(); - } - if (create) { - getUiElementNode().createXmlNode(); - } - } else { - // Users no longer wants the <application> node. - removeApplicationNode(); - } - } - }); - } - }); - } - } - - /** - * Restore a previously "saved" application node. - * - * @return True if the node could be restored, false otherwise. - */ - private boolean restoreApplicationNode() { - if (mUndoXmlDocument == null || mUndoXmlNode == null) { - return false; - } - - // Validate node references... - mUndoXmlParent = validateNode(mUndoXmlDocument, mUndoXmlParent); - mUndoXmlNextNode = validateNode(mUndoXmlDocument, mUndoXmlNextNode); - mUndoXmlNextElement = validateNode(mUndoXmlDocument, mUndoXmlNextElement); - - if (mUndoXmlParent == null){ - // If the parent node doesn't exist, try to find a new manifest node. - // If it doesn't exist, create it. - mUndoXmlParent = getUiElementNode().getUiParent().prepareCommit(); - mUndoXmlNextNode = null; - mUndoXmlNextElement = null; - } - - boolean success = false; - if (mUndoXmlParent != null) { - // If the parent is still around, reuse the same node. - - // Ideally we want to insert the node before what used to be its next sibling. - // If that's not possible, we try to insert it before its next sibling element. - // If that's not possible either, it will be inserted at the end of the parent's. - Node next = mUndoXmlNextNode; - if (next == null) { - next = mUndoXmlNextElement; - } - mUndoXmlParent.insertBefore(mUndoXmlNode, next); - if (next == null) { - Text sep = mUndoXmlDocument.createTextNode("\n"); //$NON-NLS-1$ - mUndoXmlParent.insertBefore(sep, null); // insert separator before end tag - } - success = true; - } - - // Remove internal references to avoid using them twice - mUndoXmlParent = null; - mUndoXmlNextNode = null; - mUndoXmlNextElement = null; - mUndoXmlNode = null; - mUndoXmlDocument = null; - return success; - } - - /** - * Validates that the given xml_node is still either the root node or one of its - * direct descendants. - * - * @param root_node The root of the node hierarchy to examine. - * @param xml_node The XML node to find. - * @return Returns xml_node if it is, otherwise returns null. - */ - private Node validateNode(Node root_node, Node xml_node) { - if (root_node == xml_node) { - return xml_node; - } else { - for (Node node = root_node.getFirstChild(); node != null; - node = node.getNextSibling()) { - if (root_node == xml_node || validateNode(node, xml_node) != null) { - return xml_node; - } - } - } - return null; - } - - /** - * Removes the <application> node from the hierarchy. - * Before doing that, we try to remember where it was so that we can put it back - * in the same place. - */ - private void removeApplicationNode() { - // Make sure the node actually exists... - Node xml_node = getUiElementNode().getXmlNode(); - if (xml_node == null) { - return; - } - - // Save its parent, next sibling and next element - mUndoXmlDocument = xml_node.getOwnerDocument(); - mUndoXmlParent = xml_node.getParentNode(); - mUndoXmlNextNode = xml_node.getNextSibling(); - mUndoXmlNextElement = mUndoXmlNextNode; - while (mUndoXmlNextElement != null && - mUndoXmlNextElement.getNodeType() != Node.ELEMENT_NODE) { - mUndoXmlNextElement = mUndoXmlNextElement.getNextSibling(); - } - - // Actually remove the node from the hierarchy and keep it here. - // The returned node looses its parents/siblings pointers. - mUndoXmlNode = getUiElementNode().deleteXmlNode(); - } - } - - /** - * This listener synchronizes the UI (i.e. the checkbox) with the - * actual presence of the application XML node. - */ - private class AppNodeUpdateListener implements IUiUpdateListener { - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) { - // The UiElementNode for the application XML node always exists, even - // if there is no corresponding XML node in the XML file. - // - // To update the checkbox to reflect the actual state, we just need - // to check if the XML node is null. - try { - mInternalModification = true; - boolean exists = ui_node.getXmlNode() != null; - if (mCheckbox.getSelection() != exists) { - mCheckbox.setSelection(exists); - } - } finally { - mInternalModification = false; - } - - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/InstrumentationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/InstrumentationPage.java deleted file mode 100644 index 86d0dd1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/InstrumentationPage.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * Page for instrumentation settings, part of the AndroidManifest form editor. - */ -public final class InstrumentationPage extends FormPage { - /** Page id used for switching tabs programmatically */ - public final static String PAGE_ID = "instrumentation_page"; //$NON-NLS-1$ - - /** Container editor */ - ManifestEditor mEditor; - - private UiTreeBlock mTreeBlock; - - public InstrumentationPage(ManifestEditor editor) { - super(editor, PAGE_ID, "Instrumentation"); // tab's label, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - form.setText("Android Manifest Instrumentation"); - form.setImage(AdtPlugin.getAndroidLogo()); - - UiElementNode manifest = mEditor.getUiRootNode(); - AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors(); - - ElementDescriptor[] descriptorFilters = null; - if (manifestDescriptor != null) { - descriptorFilters = new ElementDescriptor[] { - manifestDescriptor.getInstrumentationElement(), - }; - } - - mTreeBlock = new UiTreeBlock(mEditor, manifest, - true /* autoCreateRoot */, - descriptorFilters, - "Instrumentation", - "List of instrumentations defined in the manifest"); - mTreeBlock.createContent(managedForm); - } - - /** - * Changes and refreshes the Application UI node handled by the sub parts. - */ - public void refreshUiNode() { - if (mTreeBlock != null) { - UiElementNode manifest = mEditor.getUiRootNode(); - AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors(); - - mTreeBlock.changeRootAndDescriptors(manifest, - new ElementDescriptor[] { - manifestDescriptor.getInstrumentationElement() - }, - true /* refresh */); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewExportPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewExportPart.java deleted file mode 100644 index 66af84c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewExportPart.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.common.project.ExportHelper; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.ui.SectionHelper.ManifestSectionPart; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.forms.events.HyperlinkAdapter; -import org.eclipse.ui.forms.events.HyperlinkEvent; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.part.FileEditorInput; - -/** - * Export section part for overview page. - */ -final class OverviewExportPart extends ManifestSectionPart { - - private final OverviewPage mOverviewPage; - - public OverviewExportPart(OverviewPage overviewPage, Composite body, FormToolkit toolkit, ManifestEditor editor) { - super(body, toolkit, Section.TWISTIE | Section.EXPANDED, true /* description */); - mOverviewPage = overviewPage; - Section section = getSection(); - section.setText("Exporting"); - section.setDescription("To export the application for distribution, you have the following options:"); - - Composite table = createTableLayout(toolkit, 2 /* numColumns */); - - StringBuffer buf = new StringBuffer(); - buf.append("<form><li><a href=\"wizard\">"); //$NON-NLS-1$ - buf.append("Use the Export Wizard"); - buf.append("</a>"); //$NON-NLS-1$ - buf.append(" to export and sign an APK"); - buf.append("</li>"); //$NON-NLS-1$ - buf.append("<li><a href=\"manual\">"); //$NON-NLS-1$ - buf.append("Export an unsigned APK"); - buf.append("</a>"); //$NON-NLS-1$ - buf.append(" and sign it manually"); - buf.append("</li></form>"); //$NON-NLS-1$ - - FormText text = createFormText(table, toolkit, true, buf.toString(), - false /* setupLayoutData */); - text.addHyperlinkListener(new HyperlinkAdapter() { - @Override - public void linkActivated(HyperlinkEvent e) { - // get the project from the editor - IEditorInput input = mOverviewPage.mEditor.getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - IFile file = fileInput.getFile(); - IProject project = file.getProject(); - - if ("manual".equals(e.data)) { //$NON-NLS-1$ - // now we can export an unsigned apk for the project. - ExportHelper.exportProject(project); - } else { - // call the export wizard - ExportHelper.startExportWizard(project); - } - } - } - }); - - layoutChanged(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewInfoPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewInfoPart.java deleted file mode 100644 index 026b760..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewInfoPart.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.ui.UiElementPart; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.w3c.dom.Node; - -/** - * Generic info section part for overview page - */ -final class OverviewInfoPart extends UiElementPart { - - private IManagedForm mManagedForm; - - public OverviewInfoPart(Composite body, FormToolkit toolkit, ManifestEditor editor) { - super(body, toolkit, editor, - null, // uiElementNode - "General Information", // section title - "Defines general information about the AndroidManifest.xml", // section description - Section.TWISTIE | Section.EXPANDED); - } - - /** - * Retrieves the UiElementNode that this part will edit. The node must exist - * and can't be null, by design, because it's a mandatory node. - */ - private static UiElementNode getManifestUiNode(ManifestEditor editor) { - AndroidManifestDescriptors manifestDescriptors = editor.getManifestDescriptors(); - if (manifestDescriptors != null) { - ElementDescriptor desc = manifestDescriptors.getManifestElement(); - if (editor.getUiRootNode().getDescriptor() == desc) { - return editor.getUiRootNode(); - } else { - return editor.getUiRootNode().findUiChildNode(desc.getXmlName()); - } - } - - // No manifest descriptor: we have a dummy UiRootNode, so we return that. - // The editor will be reloaded once we have the proper descriptors anyway. - return editor.getUiRootNode(); - } - - /** - * Retrieves the uses-sdk UI node. Since this is a mandatory node, it *always* - * exists, even if there is no matching XML node. - */ - private UiElementNode getUsesSdkUiNode(ManifestEditor editor) { - AndroidManifestDescriptors manifestDescriptors = editor.getManifestDescriptors(); - if (manifestDescriptors != null) { - ElementDescriptor desc = manifestDescriptors.getUsesSdkElement(); - return editor.getUiRootNode().findUiChildNode(desc.getXmlName()); - } - - // No manifest descriptor: we have a dummy UiRootNode, so we return that. - // The editor will be reloaded once we have the proper descriptors anyway. - return editor.getUiRootNode(); - } - - /** - * Overridden in order to capture the current managed form. - * - * {@inheritDoc} - */ - @Override - protected void createFormControls(final IManagedForm managedForm) { - mManagedForm = managedForm; - super.createFormControls(managedForm); - } - - /** - * Removes any existing Attribute UI widgets and recreate them if the SDK has changed. - * <p/> - * This is called by {@link OverviewPage#refreshUiApplicationNode()} when the - * SDK has changed. - */ - public void onSdkChanged() { - createUiAttributes(mManagedForm); - } - - /** - * Overridden to add the description and the ui attributes of both the - * manifest and uses-sdk UI nodes. - * <p/> - * {@inheritDoc} - */ - @Override - protected void fillTable(Composite table, IManagedForm managedForm) { - int n = 0; - - UiElementNode uiNode = getManifestUiNode(getEditor()); - n += insertUiAttributes(uiNode, table, managedForm); - - uiNode = getUsesSdkUiNode(getEditor()); - n += insertUiAttributes(uiNode, table, managedForm); - - if (n == 0) { - createLabel(table, managedForm.getToolkit(), - "No attributes to display, waiting for SDK to finish loading...", - null /* tooltip */ ); - } - - layoutChanged(); - } - - /** - * Overridden to tests whether either the manifest or uses-sdk nodes parts are dirty. - * <p/> - * {@inheritDoc} - * - * @return <code>true</code> if the part is dirty, <code>false</code> - * otherwise. - */ - @Override - public boolean isDirty() { - boolean dirty = super.isDirty(); - - if (!dirty) { - UiElementNode uiNode = getManifestUiNode(getEditor()); - if (uiNode != null) { - for (UiAttributeNode ui_attr : uiNode.getUiAttributes()) { - if (ui_attr.isDirty()) { - markDirty(); - dirty = true; - break; - } - } - } - } - - if (!dirty) { - UiElementNode uiNode = getUsesSdkUiNode(getEditor()); - if (uiNode != null) { - for (UiAttributeNode ui_attr : uiNode.getUiAttributes()) { - if (ui_attr.isDirty()) { - markDirty(); - dirty = true; - break; - } - } - } - } - - return dirty; - } - - /** - * Overridden to save both the manifest or uses-sdk nodes. - * <p/> - * {@inheritDoc} - */ - @Override - public void commit(boolean onSave) { - final UiElementNode manifestUiNode = getManifestUiNode(getEditor()); - final UiElementNode usesSdkUiNode = getUsesSdkUiNode(getEditor()); - - getEditor().editXmlModel(new Runnable() { - public void run() { - if (manifestUiNode != null && manifestUiNode.isDirty()) { - for (UiAttributeNode ui_attr : manifestUiNode.getUiAttributes()) { - ui_attr.commit(); - } - } - - if (usesSdkUiNode != null && usesSdkUiNode.isDirty()) { - for (UiAttributeNode ui_attr : usesSdkUiNode.getUiAttributes()) { - ui_attr.commit(); - } - - if (!usesSdkUiNode.isDirty()) { - // Remove the <uses-sdk> XML element if it is empty. - // Rather than rely on the internal UI state, actually check that the - // XML element has no attributes and no child element so that we don't - // trash some user-generated content. - Node element = usesSdkUiNode.prepareCommit(); - if (element != null && - !element.hasAttributes() && - !element.hasChildNodes()) { - // Important note: we MUST NOT use usesSdkUiNode.deleteXmlNode() - // here, as it would clear the UiAttribute list and thus break the - // link between the controls and the ui attribute field. - // Instead what we want is simply to remove the XML node and let the - // UiElementNode node know. - Node parent = element.getParentNode(); - if (parent != null) { - parent.removeChild(element); - usesSdkUiNode.loadFromXmlNode(null /*xml_node*/); - } - } - } - } - } - }); - - // We need to call super's commit after we synchronized the nodes to make sure we - // reset the dirty flag after all the side effects from committing have occurred. - super.commit(onSave); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewLinksPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewLinksPart.java deleted file mode 100644 index d637a8f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewLinksPart.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.ui.SectionHelper.ManifestSectionPart; - -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; - -/** - * Links section part for overview page. - */ -final class OverviewLinksPart extends ManifestSectionPart { - - private final ManifestEditor mEditor; - private FormText mFormText; - - public OverviewLinksPart(Composite body, FormToolkit toolkit, ManifestEditor editor) { - super(body, toolkit, Section.TWISTIE | Section.EXPANDED, true /* description */); - mEditor = editor; - Section section = getSection(); - section.setText("Links"); - section.setDescription("The content of the Android Manifest is made up of three sections. You can also edit the XML directly."); - - Composite table = createTableLayout(toolkit, 2 /* numColumns */); - - StringBuffer buf = new StringBuffer(); - buf.append(String.format("<form><li style=\"image\" value=\"app_img\"><a href=\"page:%1$s\">", // $NON-NLS-1$ - ApplicationPage.PAGE_ID)); - buf.append("Application"); - buf.append("</a>"); //$NON-NLS-1$ - buf.append(": Activities, intent filters, providers, services and receivers."); - buf.append("</li>"); //$NON-NLS-1$ - - buf.append(String.format("<li style=\"image\" value=\"perm_img\"><a href=\"page:%1$s\">", // $NON-NLS-1$ - PermissionPage.PAGE_ID)); - buf.append("Permission"); - buf.append("</a>"); //$NON-NLS-1$ - buf.append(": Permissions defined and permissions used."); - buf.append("</li>"); //$NON-NLS-1$ - - buf.append(String.format("<li style=\"image\" value=\"inst_img\"><a href=\"page:%1$s\">", // $NON-NLS-1$ - InstrumentationPage.PAGE_ID)); - buf.append("Instrumentation"); - buf.append("</a>"); //$NON-NLS-1$ - buf.append(": Instrumentation defined."); - buf.append("</li>"); //$NON-NLS-1$ - - buf.append(String.format("<li style=\"image\" value=\"android_img\"><a href=\"page:%1$s\">", // $NON-NLS-1$ - ManifestEditor.TEXT_EDITOR_ID)); - buf.append("XML Source"); - buf.append("</a>"); //$NON-NLS-1$ - buf.append(": Directly edit the AndroidManifest.xml file."); - buf.append("</li>"); //$NON-NLS-1$ - - buf.append("<li style=\"image\" value=\"android_img\">"); // $NON-NLS-1$ - buf.append("<a href=\"http://code.google.com/android/devel/bblocks-manifest.html\">Documentation</a>: Documentation from the Android SDK for AndroidManifest.xml."); // $NON-NLS-1$ - buf.append("</li>"); //$NON-NLS-1$ - buf.append("</form>"); //$NON-NLS-1$ - - mFormText = createFormText(table, toolkit, true, buf.toString(), - false /* setupLayoutData */); - - AndroidManifestDescriptors manifestDescriptor = editor.getManifestDescriptors(); - - Image androidLogo = AdtPlugin.getAndroidLogo(); - mFormText.setImage("android_img", androidLogo); //$NON-NLS-1$ - - if (manifestDescriptor != null) { - mFormText.setImage("app_img", getIcon(manifestDescriptor.getApplicationElement())); //$NON-NLS-1$ - mFormText.setImage("perm_img", getIcon(manifestDescriptor.getPermissionElement())); //$NON-NLS-1$ - mFormText.setImage("inst_img", getIcon(manifestDescriptor.getInstrumentationElement())); //$NON-NLS-1$ - } else { - mFormText.setImage("app_img", androidLogo); //$NON-NLS-1$ - mFormText.setImage("perm_img", androidLogo); //$NON-NLS-1$ - mFormText.setImage("inst_img", androidLogo); //$NON-NLS-1$ - } - mFormText.addHyperlinkListener(editor.createHyperlinkListener()); - } - - /** - * Update the UI with information from the new descriptors. - * <p/>At this point, this only refreshes the icons. - * <p/> - * This is called by {@link OverviewPage#refreshUiApplicationNode()} when the - * SDK has changed. - */ - public void onSdkChanged() { - AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors(); - if (manifestDescriptor != null) { - mFormText.setImage("app_img", getIcon(manifestDescriptor.getApplicationElement())); //$NON-NLS-1$ - mFormText.setImage("perm_img", getIcon(manifestDescriptor.getPermissionElement())); //$NON-NLS-1$ - mFormText.setImage("inst_img", getIcon(manifestDescriptor.getInstrumentationElement())); //$NON-NLS-1$ - } - } - - private Image getIcon(ElementDescriptor desc) { - if (desc != null && desc.getIcon() != null) { - return desc.getIcon(); - } - - return AdtPlugin.getAndroidLogo(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewPage.java deleted file mode 100644 index 62954bd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/OverviewPage.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ColumnLayout; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.ScrolledForm; - - -/** - * Page for overview settings, part of the AndroidManifest form editor. - * <p/> - * Useful reference: - * <a href="http://www.eclipse.org/articles/Article-Forms/article.html"> - * http://www.eclipse.org/articles/Article-Forms/article.html</a> - */ -public final class OverviewPage extends FormPage { - - /** Page id used for switching tabs programmatically */ - final static String PAGE_ID = "overview_page"; //$NON-NLS-1$ - - /** Container editor */ - ManifestEditor mEditor; - /** Overview part (attributes for manifest) */ - private OverviewInfoPart mOverviewPart; - /** Overview link part */ - private OverviewLinksPart mOverviewLinkPart; - - public OverviewPage(ManifestEditor editor) { - super(editor, PAGE_ID, "Overview"); // tab's label, user visible, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - form.setText("Android Manifest Overview"); - form.setImage(AdtPlugin.getAndroidLogo()); - - Composite body = form.getBody(); - FormToolkit toolkit = managedForm.getToolkit(); - ColumnLayout cl = new ColumnLayout(); - cl.minNumColumns = cl.maxNumColumns = 1; - body.setLayout(cl); - mOverviewPart = new OverviewInfoPart(body, toolkit, mEditor); - managedForm.addPart(mOverviewPart); - managedForm.addPart(new OverviewExportPart(this, body, toolkit, mEditor)); - mOverviewLinkPart = new OverviewLinksPart(body, toolkit, mEditor); - managedForm.addPart(mOverviewLinkPart); - } - - /** - * Changes and refreshes the Application UI node handle by the sub parts. - */ - public void refreshUiApplicationNode() { - if (mOverviewPart != null) { - mOverviewPart.onSdkChanged(); - } - - if (mOverviewLinkPart != null) { - mOverviewLinkPart.onSdkChanged(); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/PermissionPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/PermissionPage.java deleted file mode 100644 index 41ba22e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/pages/PermissionPage.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.manifest.pages; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * Page for permissions settings, part of the AndroidManifest form editor. - * <p/> - * Useful reference: - * <a href="http://www.eclipse.org/articles/Article-Forms/article.html"> - * http://www.eclipse.org/articles/Article-Forms/article.html</a> - */ -public final class PermissionPage extends FormPage { - /** Page id used for switching tabs programmatically */ - public final static String PAGE_ID = "permission_page"; //$NON-NLS-1$ - - /** Container editor */ - ManifestEditor mEditor; - - private UiTreeBlock mTreeBlock; - - public PermissionPage(ManifestEditor editor) { - super(editor, PAGE_ID, "Permissions"); // tab label, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - form.setText("Android Manifest Permissions"); - form.setImage(AdtPlugin.getAndroidLogo()); - - UiElementNode manifest = mEditor.getUiRootNode(); - AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors(); - - ElementDescriptor[] descriptorFilters = null; - if (manifestDescriptor != null) { - descriptorFilters = new ElementDescriptor[] { - manifestDescriptor.getPermissionElement(), - manifestDescriptor.getUsesPermissionElement(), - manifestDescriptor.getPermissionGroupElement(), - manifestDescriptor.getPermissionTreeElement() - }; - } - mTreeBlock = new UiTreeBlock(mEditor, manifest, - true /* autoCreateRoot */, - descriptorFilters, - "Permissions", - "List of permissions defined and used by the manifest"); - mTreeBlock.createContent(managedForm); - } - - /** - * Changes and refreshes the Application UI node handled by the sub parts. - */ - public void refreshUiNode() { - if (mTreeBlock != null) { - UiElementNode manifest = mEditor.getUiRootNode(); - AndroidManifestDescriptors manifestDescriptor = mEditor.getManifestDescriptors(); - - mTreeBlock.changeRootAndDescriptors(manifest, - new ElementDescriptor[] { - manifestDescriptor.getPermissionElement(), - manifestDescriptor.getUsesPermissionElement(), - manifestDescriptor.getPermissionGroupElement(), - manifestDescriptor.getPermissionTreeElement() - }, - true /* refresh */); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuContentAssist.java deleted file mode 100644 index bf76d53..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuContentAssist.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.menu; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidContentAssist; - -/** - * Content Assist Processor for /res/menu XML files - */ -class MenuContentAssist extends AndroidContentAssist { - - /** - * Constructor for LayoutContentAssist - */ - public MenuContentAssist() { - super(AndroidTargetData.DESCRIPTOR_MENU); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuEditor.java deleted file mode 100644 index cff1746..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuEditor.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.menu; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidXPathFactory; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.FileEditorInput; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; - -/** - * Multi-page form editor for /res/menu XML files. - */ -public class MenuEditor extends AndroidEditor { - - public static final String ID = AndroidConstants.EDITORS_NAMESPACE + ".menu.MenuEditor"; //$NON-NLS-1$ - - /** Root node of the UI element hierarchy */ - private UiElementNode mUiRootNode; - - /** - * Creates the form editor for resources XML files. - */ - public MenuEditor() { - super(); - } - - /** - * Returns the root node of the UI element hierarchy, which here is - * the "menu" node. - */ - @Override - public UiElementNode getUiRootNode() { - return mUiRootNode; - } - - // ---- Base Class Overrides ---- - - /** - * Returns whether the "save as" operation is supported by this editor. - * <p/> - * Save-As is a valid operation for the ManifestEditor since it acts on a - * single source file. - * - * @see IEditorPart - */ - @Override - public boolean isSaveAsAllowed() { - return true; - } - - /** - * Create the various form pages. - */ - @Override - protected void createFormPages() { - try { - addPage(new MenuTreePage(this)); - } catch (PartInitException e) { - AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$ - } - - } - - /* (non-java doc) - * Change the tab/title name to include the project name. - */ - @Override - protected void setInput(IEditorInput input) { - super.setInput(input); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput) input; - IFile file = fileInput.getFile(); - setPartName(String.format("%1$s", file.getName())); - } - } - - /** - * Processes the new XML Model, which XML root node is given. - * - * @param xml_doc The XML document, if available, or null if none exists. - */ - @Override - protected void xmlModelChanged(Document xml_doc) { - // init the ui root on demand - initUiRootNode(false /*force*/); - - mUiRootNode.setXmlDocument(xml_doc); - if (xml_doc != null) { - ElementDescriptor root_desc = mUiRootNode.getDescriptor(); - try { - XPath xpath = AndroidXPathFactory.newXPath(); - Node node = (Node) xpath.evaluate("/" + root_desc.getXmlName(), //$NON-NLS-1$ - xml_doc, - XPathConstants.NODE); - if (node == null && root_desc.isMandatory()) { - // Create the root element if it doesn't exist yet (for empty new documents) - node = mUiRootNode.createXmlNode(); - } - - // Refresh the manifest UI node and all its descendants - mUiRootNode.loadFromXmlNode(node); - - // TODO ? startMonitoringMarkers(); - } catch (XPathExpressionException e) { - AdtPlugin.log(e, "XPath error when trying to find '%s' element in XML.", //$NON-NLS-1$ - root_desc.getXmlName()); - } - } - - super.xmlModelChanged(xml_doc); - } - - /** - * Creates the initial UI Root Node, including the known mandatory elements. - * @param force if true, a new UiRootNode is recreated even if it already exists. - */ - @Override - protected void initUiRootNode(boolean force) { - // The root UI node is always created, even if there's no corresponding XML node. - if (mUiRootNode == null || force) { - Document doc = null; - if (mUiRootNode != null) { - doc = mUiRootNode.getXmlDocument(); - } - - // get the target data from the opened file (and its project) - AndroidTargetData data = getTargetData(); - - ElementDescriptor desc; - if (data == null) { - desc = new ElementDescriptor("temp", null /*children*/); - } else { - desc = data.getMenuDescriptors().getDescriptor(); - } - - mUiRootNode = desc.createUiNode(); - mUiRootNode.setEditor(this); - - onDescriptorsChanged(doc); - } - } - - // ---- Local Methods ---- - - /** - * Reloads the UI manifest node from the XML, and calls the pages to update. - */ - private void onDescriptorsChanged(Document document) { - if (document != null) { - mUiRootNode.loadFromXmlNode(document); - } else { - mUiRootNode.reloadFromXmlNode(mUiRootNode.getXmlNode()); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuSourceViewerConfig.java deleted file mode 100644 index a5e3b09..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuSourceViewerConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.menu; - - -import com.android.ide.eclipse.editors.AndroidSourceViewerConfig; - -/** - * Source Viewer Configuration that calls in MenuContentAssist. - */ -public class MenuSourceViewerConfig extends AndroidSourceViewerConfig { - - public MenuSourceViewerConfig() { - super(new MenuContentAssist()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuTreePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuTreePage.java deleted file mode 100644 index edbfa5e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/MenuTreePage.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.menu; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * Page for the menu form editor. - */ -public final class MenuTreePage extends FormPage { - /** Page id used for switching tabs programmatically */ - public final static String PAGE_ID = "layout_tree_page"; //$NON-NLS-1$ - - /** Container editor */ - MenuEditor mEditor; - - public MenuTreePage(MenuEditor editor) { - super(editor, PAGE_ID, "Layout"); // tab's label, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - form.setText("Android Menu"); - form.setImage(AdtPlugin.getAndroidLogo()); - - UiElementNode rootNode = mEditor.getUiRootNode(); - UiTreeBlock block = new UiTreeBlock(mEditor, rootNode, - true /* autoCreateRoot */, - null /* no element filters */, - "Menu Elements", - "List of all menu elements in this XML file."); - block.createContent(managedForm); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java deleted file mode 100644 index 40a8f16..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/menu/descriptors/MenuDescriptors.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.menu.descriptors; - -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.sdklib.SdkConstants; - -import java.util.ArrayList; -import java.util.Map; - - -/** - * Complete description of the menu structure. - */ -public final class MenuDescriptors implements IDescriptorProvider { - - public static final String MENU_ROOT_ELEMENT = "menu"; //$NON-NLS-1$ - - /** The root element descriptor. */ - private ElementDescriptor mDescriptor = null; - - /** @return the root descriptor. */ - public ElementDescriptor getDescriptor() { - return mDescriptor; - } - - public ElementDescriptor[] getRootElementDescriptors() { - return mDescriptor.getChildren(); - } - - /** - * Updates the document descriptor. - * <p/> - * It first computes the new children of the descriptor and then updates them - * all at once. - * - * @param styleMap The map style => attributes from the attrs.xml file - */ - public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { - - // There are 3 elements: menu, item and group. - // The root element MUST be a menu. - // A top menu can contain items or group: - // - top groups can contain top items - // - top items can contain sub-menus - // A sub menu can contains sub items or sub groups: - // - sub groups can contain sub items - // - sub items cannot contain anything - - if (mDescriptor == null) { - mDescriptor = createElement(styleMap, - MENU_ROOT_ELEMENT, // xmlName - "Menu", // uiName, - null, // TODO SDK URL - null, // extraAttribute - null, // childrenElements, - true /* mandatory */); - } - - // -- sub menu can have sub_items, sub_groups but not sub_menus - - ElementDescriptor sub_item = createElement(styleMap, - "item", // xmlName //$NON-NLS-1$ - "Item", // uiName, - null, // TODO SDK URL - null, // extraAttribute - null, // childrenElements, - false /* mandatory */); - - ElementDescriptor sub_group = createElement(styleMap, - "group", // xmlName //$NON-NLS-1$ - "Group", // uiName, - null, // TODO SDK URL - null, // extraAttribute - new ElementDescriptor[] { sub_item }, // childrenElements, - false /* mandatory */); - - ElementDescriptor sub_menu = createElement(styleMap, - MENU_ROOT_ELEMENT, // xmlName //$NON-NLS-1$ - "Sub-Menu", // uiName, - null, // TODO SDK URL - null, // extraAttribute - new ElementDescriptor[] { sub_item, sub_group }, // childrenElements, - true /* mandatory */); - - // -- top menu can have all top groups and top items (which can have sub menus) - - ElementDescriptor top_item = createElement(styleMap, - "item", // xmlName //$NON-NLS-1$ - "Item", // uiName, - null, // TODO SDK URL - null, // extraAttribute - new ElementDescriptor[] { sub_menu }, // childrenElements, - false /* mandatory */); - - ElementDescriptor top_group = createElement(styleMap, - "group", // xmlName //$NON-NLS-1$ - "Group", // uiName, - null, // TODO SDK URL - null, // extraAttribute - new ElementDescriptor[] { top_item }, // childrenElements, - false /* mandatory */); - - XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor("android", //$NON-NLS-1$ - SdkConstants.NS_RESOURCES); - - updateElement(mDescriptor, styleMap, "Menu", xmlns); //$NON-NLS-1$ - mDescriptor.setChildren(new ElementDescriptor[] { top_item, top_group }); - } - - /** - * Returns a new ElementDescriptor constructed from the information given here - * and the javadoc & attributes extracted from the style map if any. - */ - private ElementDescriptor createElement( - Map<String, DeclareStyleableInfo> styleMap, - String xmlName, String uiName, String sdkUrl, - AttributeDescriptor extraAttribute, - ElementDescriptor[] childrenElements, boolean mandatory) { - - ElementDescriptor element = new ElementDescriptor(xmlName, uiName, null, sdkUrl, - null, childrenElements, mandatory); - - return updateElement(element, styleMap, - getStyleName(xmlName), - extraAttribute); - } - - /** - * Updates an ElementDescriptor with the javadoc & attributes extracted from the style - * map if any. - */ - private ElementDescriptor updateElement(ElementDescriptor element, - Map<String, DeclareStyleableInfo> styleMap, - String styleName, - AttributeDescriptor extraAttribute) { - ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>(); - - DeclareStyleableInfo style = styleMap != null ? styleMap.get(styleName) : null; - if (style != null) { - DescriptorsUtils.appendAttributes(descs, - null, // elementName - SdkConstants.NS_RESOURCES, - style.getAttributes(), - null, // requiredAttributes - null); // overrides - element.setTooltip(style.getJavaDoc()); - } - - if (extraAttribute != null) { - descs.add(extraAttribute); - } - - element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()])); - return element; - } - - /** - * Returns the style name (i.e. the <declare-styleable> name found in attrs.xml) - * for a given XML element name. - * <p/> - * The rule is that all elements have for style name: - * - their xml name capitalized - * - a "Menu" prefix, except for <menu> itself which is just "Menu". - */ - private String getStyleName(String xmlName) { - String styleName = DescriptorsUtils.capitalize(xmlName); - - // This is NOT the UI Name but the expected internal style name - final String MENU_STYLE_BASE_NAME = "Menu"; //$NON-NLS-1$ - - if (!styleName.equals(MENU_STYLE_BASE_NAME)) { - styleName = MENU_STYLE_BASE_NAME + styleName; - } - return styleName; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesContentAssist.java deleted file mode 100644 index c9c8e17..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesContentAssist.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidContentAssist; - -/** - * Content Assist Processor for /res/values and /res/drawable XML files - */ -class ResourcesContentAssist extends AndroidContentAssist { - - /** - * Constructor for ResourcesContentAssist - */ - public ResourcesContentAssist() { - super(AndroidTargetData.DESCRIPTOR_RESOURCES); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesEditor.java deleted file mode 100644 index 46a9112..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesEditor.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidXPathFactory; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.FileEditorInput; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; - -/** - * Multi-page form editor for /res/values and /res/drawable XML files. - */ -public class ResourcesEditor extends AndroidEditor { - - public static final String ID = AndroidConstants.EDITORS_NAMESPACE + ".resources.ResourcesEditor"; //$NON-NLS-1$ - - /** Root node of the UI element hierarchy */ - private UiElementNode mUiResourcesNode; - - - /** - * Creates the form editor for resources XML files. - */ - public ResourcesEditor() { - super(); - } - - /** - * Returns the root node of the UI element hierarchy, which - * here is the "resources" node. - */ - @Override - public UiElementNode getUiRootNode() { - return mUiResourcesNode; - } - - // ---- Base Class Overrides ---- - - /** - * Returns whether the "save as" operation is supported by this editor. - * <p/> - * Save-As is a valid operation for the ManifestEditor since it acts on a - * single source file. - * - * @see IEditorPart - */ - @Override - public boolean isSaveAsAllowed() { - return true; - } - - /** - * Create the various form pages. - */ - @Override - protected void createFormPages() { - try { - addPage(new ResourcesTreePage(this)); - } catch (PartInitException e) { - AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$ - AdtPlugin.getDefault().getLog().log(e.getStatus()); - } - } - - /* (non-java doc) - * Change the tab/title name to include the project name. - */ - @Override - protected void setInput(IEditorInput input) { - super.setInput(input); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput) input; - IFile file = fileInput.getFile(); - setPartName(String.format("%1$s", - file.getName())); - } - } - - /** - * Processes the new XML Model, which XML root node is given. - * - * @param xml_doc The XML document, if available, or null if none exists. - */ - @Override - protected void xmlModelChanged(Document xml_doc) { - // init the ui root on demand - initUiRootNode(false /*force*/); - - mUiResourcesNode.setXmlDocument(xml_doc); - if (xml_doc != null) { - ElementDescriptor resources_desc = - ResourcesDescriptors.getInstance().getElementDescriptor(); - try { - XPath xpath = AndroidXPathFactory.newXPath(); - Node node = (Node) xpath.evaluate("/" + resources_desc.getXmlName(), //$NON-NLS-1$ - xml_doc, - XPathConstants.NODE); - assert node != null && node.getNodeName().equals(resources_desc.getXmlName()); - - // Refresh the manifest UI node and all its descendants - mUiResourcesNode.loadFromXmlNode(node); - } catch (XPathExpressionException e) { - AdtPlugin.log(e, "XPath error when trying to find '%s' element in XML.", //$NON-NLS-1$ - resources_desc.getXmlName()); - } - } - - super.xmlModelChanged(xml_doc); - } - - /** - * Creates the initial UI Root Node, including the known mandatory elements. - * @param force if true, a new UiRootNode is recreated even if it already exists. - */ - @Override - protected void initUiRootNode(boolean force) { - // The manifest UI node is always created, even if there's no corresponding XML node. - if (mUiResourcesNode == null || force) { - ElementDescriptor resources_desc = - ResourcesDescriptors.getInstance().getElementDescriptor(); - mUiResourcesNode = resources_desc.createUiNode(); - mUiResourcesNode.setEditor(this); - - onDescriptorsChanged(); - } - } - - // ---- Local Methods ---- - - private void onDescriptorsChanged() { - // nothing to be done, as the descriptor are static for now. - // FIXME Update when the descriptors are not static - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesSourceViewerConfig.java deleted file mode 100644 index 1804312..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesSourceViewerConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources; - - -import com.android.ide.eclipse.editors.AndroidSourceViewerConfig; - -/** - * Source Viewer Configuration that calls in ResourcesContentAssist. - */ -public class ResourcesSourceViewerConfig extends AndroidSourceViewerConfig { - - public ResourcesSourceViewerConfig() { - super(new ResourcesContentAssist()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesTreePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesTreePage.java deleted file mode 100644 index 5c1b0e1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/ResourcesTreePage.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolder; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.resources.IFile; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; -import org.eclipse.ui.part.FileEditorInput; - -/** - * Page for instrumentation settings, part of the AndroidManifest form editor. - */ -public final class ResourcesTreePage extends FormPage { - /** Page id used for switching tabs programmatically */ - public final static String PAGE_ID = "res_tree_page"; //$NON-NLS-1$ - - /** Container editor */ - ResourcesEditor mEditor; - - public ResourcesTreePage(ResourcesEditor editor) { - super(editor, PAGE_ID, "Resources"); // tab's label, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - - String configText = null; - IEditorInput input = mEditor.getEditorInput(); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput)input; - IFile iFile = fileInput.getFile(); - - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(iFile); - if (resFolder != null) { - configText = resFolder.getConfiguration().toDisplayString(); - } - } - - if (configText != null) { - form.setText(String.format("Android Resources (%1$s)", configText)); - } else { - form.setText("Android Resources"); - } - - form.setImage(AdtPlugin.getAndroidLogo()); - - UiElementNode resources = mEditor.getUiRootNode(); - UiTreeBlock block = new UiTreeBlock(mEditor, resources, - true /* autoCreateRoot */, - null /* no element filters */, - "Resources Elements", - "List of all resources elements in this XML file."); - block.createContent(managedForm); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java deleted file mode 100644 index 9a61d17..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Resource Qualifier for Mobile Country Code. - */ -public final class CountryCodeQualifier extends ResourceQualifier { - /** Default pixel density value. This means the property is not set. */ - private final static int DEFAULT_CODE = -1; - - private final static Pattern sCountryCodePattern = Pattern.compile("^mcc(\\d{3})$");//$NON-NLS-1$ - - private int mCode = DEFAULT_CODE; - - public static final String NAME = "Mobile Country Code"; - - /** - * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, - * <code>null</code> is returned. - * @param segment the folder segment from which to create a qualifier. - * @return a new {@link CountryCodeQualifier} object or <code>null</code> - */ - public static CountryCodeQualifier getQualifier(String segment) { - Matcher m = sCountryCodePattern.matcher(segment); - if (m.matches()) { - String v = m.group(1); - - int code = -1; - try { - code = Integer.parseInt(v); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid number. - return null; - } - - CountryCodeQualifier qualifier = new CountryCodeQualifier(); - qualifier.mCode = code; - return qualifier; - } - - return null; - } - - /** - * Returns the folder name segment for the given value. This is equivalent to calling - * {@link #toString()} on a {@link CountryCodeQualifier} object. - * @param code the value of the qualifier, as returned by {@link #getCode()}. - */ - public static String getFolderSegment(int code) { - if (code != DEFAULT_CODE && code >= 100 && code <=999) { // code is 3 digit.) { - return String.format("mcc%1$d", code); //$NON-NLS-1$ - } - - return ""; //$NON-NLS-1$ - } - - public int getCode() { - return mCode; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Country Code"; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("mcc"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mCode != DEFAULT_CODE; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - CountryCodeQualifier qualifier = getQualifier(value); - if (qualifier != null) { - config.setCountryCodeQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof CountryCodeQualifier) { - return mCode == ((CountryCodeQualifier)qualifier).mCode; - } - - return false; - } - - @Override - public int hashCode() { - return mCode; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - return getFolderSegment(mCode); - } - - @Override - public String getStringValue() { - if (mCode != DEFAULT_CODE) { - return String.format("MCC %1$d", mCode); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/FolderConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/FolderConfiguration.java deleted file mode 100644 index 3c3e11f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/FolderConfiguration.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; - - -/** - * Represents the configuration for Resource Folders. All the properties have a default - * value which means that the property is not set. - */ -public final class FolderConfiguration implements Comparable<FolderConfiguration> { - public final static String QUALIFIER_SEP = "-"; //$NON-NLS-1$ - - private final ResourceQualifier[] mQualifiers = new ResourceQualifier[INDEX_COUNT]; - - private final static int INDEX_COUNTRY_CODE = 0; - private final static int INDEX_NETWORK_CODE = 1; - private final static int INDEX_LANGUAGE = 2; - private final static int INDEX_REGION = 3; - private final static int INDEX_SCREEN_ORIENTATION = 4; - private final static int INDEX_PIXEL_DENSITY = 5; - private final static int INDEX_TOUCH_TYPE = 6; - private final static int INDEX_KEYBOARD_STATE = 7; - private final static int INDEX_TEXT_INPUT_METHOD = 8; - private final static int INDEX_NAVIGATION_METHOD = 9; - private final static int INDEX_SCREEN_DIMENSION = 10; - private final static int INDEX_COUNT = 11; - - /** - * Sets the config from the qualifiers of a given <var>config</var>. - * @param config - */ - public void set(FolderConfiguration config) { - for (int i = 0 ; i < INDEX_COUNT ; i++) { - mQualifiers[i] = config.mQualifiers[i]; - } - } - - /** - * Removes the qualifiers from the receiver if they are present (and valid) - * in the given configuration. - */ - public void substract(FolderConfiguration config) { - for (int i = 0 ; i < INDEX_COUNT ; i++) { - if (config.mQualifiers[i] != null && config.mQualifiers[i].isValid()) { - mQualifiers[i] = null; - } - } - } - - /** - * Returns the first invalid qualifier, or <code>null<code> if they are all valid (or if none - * exists). - */ - public ResourceQualifier getInvalidQualifier() { - for (int i = 0 ; i < INDEX_COUNT ; i++) { - if (mQualifiers[i] != null && mQualifiers[i].isValid() == false) { - return mQualifiers[i]; - } - } - - // all allocated qualifiers are valid, we return null. - return null; - } - - /** - * Returns whether the Region qualifier is valid. Region qualifier can only be present if a - * Language qualifier is present as well. - * @return true if the Region qualifier is valid. - */ - public boolean checkRegion() { - if (mQualifiers[INDEX_LANGUAGE] == null && mQualifiers[INDEX_REGION] != null) { - return false; - } - - return true; - } - - /** - * Adds a qualifier to the {@link FolderConfiguration} - * @param qualifier the {@link ResourceQualifier} to add. - */ - public void addQualifier(ResourceQualifier qualifier) { - if (qualifier instanceof CountryCodeQualifier) { - mQualifiers[INDEX_COUNTRY_CODE] = qualifier; - } else if (qualifier instanceof NetworkCodeQualifier) { - mQualifiers[INDEX_NETWORK_CODE] = qualifier; - } else if (qualifier instanceof LanguageQualifier) { - mQualifiers[INDEX_LANGUAGE] = qualifier; - } else if (qualifier instanceof RegionQualifier) { - mQualifiers[INDEX_REGION] = qualifier; - } else if (qualifier instanceof ScreenOrientationQualifier) { - mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier; - } else if (qualifier instanceof PixelDensityQualifier) { - mQualifiers[INDEX_PIXEL_DENSITY] = qualifier; - } else if (qualifier instanceof TouchScreenQualifier) { - mQualifiers[INDEX_TOUCH_TYPE] = qualifier; - } else if (qualifier instanceof KeyboardStateQualifier) { - mQualifiers[INDEX_KEYBOARD_STATE] = qualifier; - } else if (qualifier instanceof TextInputMethodQualifier) { - mQualifiers[INDEX_TEXT_INPUT_METHOD] = qualifier; - } else if (qualifier instanceof NavigationMethodQualifier) { - mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier; - } else if (qualifier instanceof ScreenDimensionQualifier) { - mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier; - } - } - - /** - * Removes a given qualifier from the {@link FolderConfiguration}. - * @param qualifier the {@link ResourceQualifier} to remove. - */ - public void removeQualifier(ResourceQualifier qualifier) { - for (int i = 0 ; i < INDEX_COUNT ; i++) { - if (mQualifiers[i] == qualifier) { - mQualifiers[i] = null; - return; - } - } - } - - public void setCountryCodeQualifier(CountryCodeQualifier qualifier) { - mQualifiers[INDEX_COUNTRY_CODE] = qualifier; - } - - public CountryCodeQualifier getCountryCodeQualifier() { - return (CountryCodeQualifier)mQualifiers[INDEX_COUNTRY_CODE]; - } - - public void setNetworkCodeQualifier(NetworkCodeQualifier qualifier) { - mQualifiers[INDEX_NETWORK_CODE] = qualifier; - } - - public NetworkCodeQualifier getNetworkCodeQualifier() { - return (NetworkCodeQualifier)mQualifiers[INDEX_NETWORK_CODE]; - } - - public void setLanguageQualifier(LanguageQualifier qualifier) { - mQualifiers[INDEX_LANGUAGE] = qualifier; - } - - public LanguageQualifier getLanguageQualifier() { - return (LanguageQualifier)mQualifiers[INDEX_LANGUAGE]; - } - - public void setRegionQualifier(RegionQualifier qualifier) { - mQualifiers[INDEX_REGION] = qualifier; - } - - public RegionQualifier getRegionQualifier() { - return (RegionQualifier)mQualifiers[INDEX_REGION]; - } - - public void setScreenOrientationQualifier(ScreenOrientationQualifier qualifier) { - mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier; - } - - public ScreenOrientationQualifier getScreenOrientationQualifier() { - return (ScreenOrientationQualifier)mQualifiers[INDEX_SCREEN_ORIENTATION]; - } - - public void setPixelDensityQualifier(PixelDensityQualifier qualifier) { - mQualifiers[INDEX_PIXEL_DENSITY] = qualifier; - } - - public PixelDensityQualifier getPixelDensityQualifier() { - return (PixelDensityQualifier)mQualifiers[INDEX_PIXEL_DENSITY]; - } - - public void setTouchTypeQualifier(TouchScreenQualifier qualifier) { - mQualifiers[INDEX_TOUCH_TYPE] = qualifier; - } - - public TouchScreenQualifier getTouchTypeQualifier() { - return (TouchScreenQualifier)mQualifiers[INDEX_TOUCH_TYPE]; - } - - public void setKeyboardStateQualifier(KeyboardStateQualifier qualifier) { - mQualifiers[INDEX_KEYBOARD_STATE] = qualifier; - } - - public KeyboardStateQualifier getKeyboardStateQualifier() { - return (KeyboardStateQualifier)mQualifiers[INDEX_KEYBOARD_STATE]; - } - - public void setTextInputMethodQualifier(TextInputMethodQualifier qualifier) { - mQualifiers[INDEX_TEXT_INPUT_METHOD] = qualifier; - } - - public TextInputMethodQualifier getTextInputMethodQualifier() { - return (TextInputMethodQualifier)mQualifiers[INDEX_TEXT_INPUT_METHOD]; - } - - public void setNavigationMethodQualifier(NavigationMethodQualifier qualifier) { - mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier; - } - - public NavigationMethodQualifier getNavigationMethodQualifier() { - return (NavigationMethodQualifier)mQualifiers[INDEX_NAVIGATION_METHOD]; - } - - public void setScreenDimensionQualifier(ScreenDimensionQualifier qualifier) { - mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier; - } - - public ScreenDimensionQualifier getScreenDimensionQualifier() { - return (ScreenDimensionQualifier)mQualifiers[INDEX_SCREEN_DIMENSION]; - } - - /** - * Returns whether an object is equals to the receiver. - */ - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof FolderConfiguration) { - FolderConfiguration fc = (FolderConfiguration)obj; - for (int i = 0 ; i < INDEX_COUNT ; i++) { - ResourceQualifier qualifier = mQualifiers[i]; - ResourceQualifier fcQualifier = fc.mQualifiers[i]; - if (qualifier != null) { - if (qualifier.equals(fcQualifier) == false) { - return false; - } - } else if (fcQualifier != null) { - return false; - } - } - - return true; - } - - return false; - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - /** - * Returns whether the Configuration has only default values. - */ - public boolean isDefault() { - for (ResourceQualifier irq : mQualifiers) { - if (irq != null) { - return false; - } - } - - return true; - } - - /** - * Returns the name of a folder with the configuration. - */ - public String getFolderName(ResourceFolderType folder) { - StringBuilder result = new StringBuilder(folder.getName()); - - for (ResourceQualifier qualifier : mQualifiers) { - if (qualifier != null) { - result.append(QUALIFIER_SEP); - result.append(qualifier.toString()); - } - } - - return result.toString(); - } - - /** - * Returns a string valid for usage in a folder name, or <code>null</code> if the configuration - * is default. - */ - @Override - public String toString() { - StringBuilder result = null; - - for (ResourceQualifier irq : mQualifiers) { - if (irq != null) { - if (result == null) { - result = new StringBuilder(); - } else { - result.append(QUALIFIER_SEP); - } - result.append(irq.toString()); - } - } - - if (result != null) { - return result.toString(); - } else { - return null; - } - } - - /** - * Returns a string valid for display purpose. - */ - public String toDisplayString() { - if (isDefault()) { - return "default"; - } - - StringBuilder result = null; - int index = 0; - ResourceQualifier qualifier = null; - - // pre- language/region qualifiers - while (index < INDEX_LANGUAGE) { - qualifier = mQualifiers[index++]; - if (qualifier != null) { - if (result == null) { - result = new StringBuilder(); - } else { - result.append(", "); //$NON-NLS-1$ - } - result.append(qualifier.getStringValue()); - - } - } - - // process the language/region qualifier in a custom way, if there are both non null. - if (mQualifiers[INDEX_LANGUAGE] != null && mQualifiers[INDEX_REGION] != null) { - String language = mQualifiers[INDEX_LANGUAGE].getStringValue(); - String region = mQualifiers[INDEX_REGION].getStringValue(); - - if (result == null) { - result = new StringBuilder(); - } else { - result.append(", "); //$NON-NLS-1$ - } - result.append(String.format("%s_%s", language, region)); //$NON-NLS-1$ - - index += 2; - } - - // post language/region qualifiers. - while (index < INDEX_COUNT) { - qualifier = mQualifiers[index++]; - if (qualifier != null) { - if (result == null) { - result = new StringBuilder(); - } else { - result.append(", "); //$NON-NLS-1$ - } - result.append(qualifier.getStringValue()); - - } - } - - return result.toString(); - } - - public int compareTo(FolderConfiguration folderConfig) { - // default are always at the top. - if (isDefault()) { - if (folderConfig.isDefault()) { - return 0; - } - return -1; - } - - // now we compare the qualifiers - for (int i = 0 ; i < INDEX_COUNT; i++) { - ResourceQualifier qualifier1 = mQualifiers[i]; - ResourceQualifier qualifier2 = folderConfig.mQualifiers[i]; - - if (qualifier1 == null) { - if (qualifier2 == null) { - continue; - } else { - return -1; - } - } else { - if (qualifier2 == null) { - return 1; - } else { - int result = qualifier1.compareTo(qualifier2); - - if (result == 0) { - continue; - } - - return result; - } - } - } - - // if we arrive here, all the qualifier matches - return 0; - } - - /** - * Returns whether the configuration match the given reference config. - * <p/>A match means that: - * <ul> - * <li>This config does not use any qualifier not used by the reference config</li> - * <li>The qualifier used by this config have the same values as the qualifiers of - * the reference config.</li> - * </ul> - * @param referenceConfig The reference configuration to test against. - * @return the number of matching qualifiers or -1 if the configurations are not compatible. - */ - public int match(FolderConfiguration referenceConfig) { - int matchCount = 0; - - for (int i = 0 ; i < INDEX_COUNT ; i++) { - ResourceQualifier testQualifier = mQualifiers[i]; - ResourceQualifier referenceQualifier = referenceConfig.mQualifiers[i]; - - // we only care if testQualifier is non null. If it's null, it's a match but - // without increasing the matchCount. - if (testQualifier != null) { - if (referenceQualifier == null) { - return -1; - } else if (testQualifier.equals(referenceQualifier) == false) { - return -1; - } - - // the qualifier match, increment the count - matchCount++; - } - } - return matchCount; - } - - /** - * Returns the index of the first non null {@link ResourceQualifier} starting at index - * <var>startIndex</var> - * @param startIndex - * @return -1 if no qualifier was found. - */ - public int getHighestPriorityQualifier(int startIndex) { - for (int i = startIndex ; i < INDEX_COUNT ; i++) { - if (mQualifiers[i] != null) { - return i; - } - } - - return -1; - } - - /** - * Create default qualifiers. - */ - public void createDefault() { - mQualifiers[INDEX_COUNTRY_CODE] = new CountryCodeQualifier(); - mQualifiers[INDEX_NETWORK_CODE] = new NetworkCodeQualifier(); - mQualifiers[INDEX_LANGUAGE] = new LanguageQualifier(); - mQualifiers[INDEX_REGION] = new RegionQualifier(); - mQualifiers[INDEX_SCREEN_ORIENTATION] = new ScreenOrientationQualifier(); - mQualifiers[INDEX_PIXEL_DENSITY] = new PixelDensityQualifier(); - mQualifiers[INDEX_TOUCH_TYPE] = new TouchScreenQualifier(); - mQualifiers[INDEX_KEYBOARD_STATE] = new KeyboardStateQualifier(); - mQualifiers[INDEX_TEXT_INPUT_METHOD] = new TextInputMethodQualifier(); - mQualifiers[INDEX_NAVIGATION_METHOD] = new NavigationMethodQualifier(); - mQualifiers[INDEX_SCREEN_DIMENSION] = new ScreenDimensionQualifier(); - } - - /** - * Returns an array of all the non null qualifiers. - */ - public ResourceQualifier[] getQualifiers() { - int count = 0; - for (int i = 0 ; i < INDEX_COUNT ; i++) { - if (mQualifiers[i] != null) { - count++; - } - } - - ResourceQualifier[] array = new ResourceQualifier[count]; - int index = 0; - for (int i = 0 ; i < INDEX_COUNT ; i++) { - if (mQualifiers[i] != null) { - array[index++] = mQualifiers[i]; - } - } - - return array; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/KeyboardStateQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/KeyboardStateQualifier.java deleted file mode 100644 index ad232ed..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/KeyboardStateQualifier.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - - - -/** - * Resource Qualifier for keyboard state. - */ -public final class KeyboardStateQualifier extends ResourceQualifier { - - public static final String NAME = "Keyboard State"; - - private KeyboardState mValue = null; - - /** - * Screen Orientation enum. - */ - public static enum KeyboardState { - EXPOSED("keysexposed", "Exposed"), //$NON-NLS-1$ - HIDDEN("keyshidden", "Hidden"); //$NON-NLS-1$ - - private String mValue; - private String mDisplayValue; - - private KeyboardState(String value, String displayValue) { - mValue = value; - mDisplayValue = displayValue; - } - - /** - * Returns the enum for matching the provided qualifier value. - * @param value The qualifier value. - * @return the enum for the qualifier value or null if no matching was found. - */ - static KeyboardState getEnum(String value) { - for (KeyboardState orient : values()) { - if (orient.mValue.equals(value)) { - return orient; - } - } - - return null; - } - - public String getValue() { - return mValue; - } - - public String getDisplayValue() { - return mDisplayValue; - } - - public static int getIndex(KeyboardState value) { - int i = 0; - for (KeyboardState input : values()) { - if (value == input) { - return i; - } - - i++; - } - - return -1; - } - - public static KeyboardState getByIndex(int index) { - int i = 0; - for (KeyboardState value : values()) { - if (i == index) { - return value; - } - i++; - } - return null; - } - } - - public KeyboardStateQualifier() { - // pass - } - - public KeyboardStateQualifier(KeyboardState value) { - mValue = value; - } - - public KeyboardState getValue() { - return mValue; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Keyboard"; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("keyboard"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - KeyboardState orientation = KeyboardState.getEnum(value); - if (orientation != null) { - KeyboardStateQualifier qualifier = new KeyboardStateQualifier(); - qualifier.mValue = orientation; - config.setKeyboardStateQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof KeyboardStateQualifier) { - return mValue == ((KeyboardStateQualifier)qualifier).mValue; - } - - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - if (mValue != null) { - return mValue.getValue(); - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue.getDisplayValue(); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/LanguageQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/LanguageQualifier.java deleted file mode 100644 index 99c3a43..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/LanguageQualifier.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -import java.util.regex.Pattern; - -/** - * Resource Qualifier for Language. - */ -public final class LanguageQualifier extends ResourceQualifier { - private final static Pattern sLanguagePattern = Pattern.compile("^[a-z]{2}$"); //$NON-NLS-1$ - - public static final String NAME = "Language"; - - private String mValue; - - /** - * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, - * <code>null</code> is returned. - * @param segment the folder segment from which to create a qualifier. - * @return a new {@link LanguageQualifier} object or <code>null</code> - */ - public static LanguageQualifier getQualifier(String segment) { - if (sLanguagePattern.matcher(segment).matches()) { - LanguageQualifier qualifier = new LanguageQualifier(); - qualifier.mValue = segment; - - return qualifier; - } - return null; - } - - /** - * Returns the folder name segment for the given value. This is equivalent to calling - * {@link #toString()} on a {@link LanguageQualifier} object. - * @param value the value of the qualifier, as returned by {@link #getValue()}. - */ - public static String getFolderSegment(String value) { - String segment = value.toLowerCase(); - if (sLanguagePattern.matcher(segment).matches()) { - return segment; - } - - return null; - } - - public String getValue() { - if (mValue != null) { - return mValue; - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return NAME; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("language"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - LanguageQualifier qualifier = getQualifier(value); - if (qualifier != null) { - config.setLanguageQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof LanguageQualifier) { - if (mValue == null) { - return ((LanguageQualifier)qualifier).mValue == null; - } - return mValue.equals(((LanguageQualifier)qualifier).mValue); - } - - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - if (mValue != null) { - return getFolderSegment(mValue); - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue; - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NavigationMethodQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NavigationMethodQualifier.java deleted file mode 100644 index 1a2cf53..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NavigationMethodQualifier.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - - - -/** - * Resource Qualifier for Navigation Method. - */ -public final class NavigationMethodQualifier extends ResourceQualifier { - - public static final String NAME = "Navigation Method"; - - private NavigationMethod mValue; - - /** - * Navigation Method enum. - */ - public static enum NavigationMethod { - DPAD("dpad", "D-pad"), //$NON-NLS-1$ - TRACKBALL("trackball", "Trackball"), //$NON-NLS-1$ - WHEEL("wheel", "Wheel"), //$NON-NLS-1$ - NONAV("nonav", "No Navigation"); //$NON-NLS-1$ - - private String mValue; - private String mDisplay; - - private NavigationMethod(String value, String display) { - mValue = value; - mDisplay = display; - } - - /** - * Returns the enum for matching the provided qualifier value. - * @param value The qualifier value. - * @return the enum for the qualifier value or null if no matching was found. - */ - static NavigationMethod getEnum(String value) { - for (NavigationMethod orient : values()) { - if (orient.mValue.equals(value)) { - return orient; - } - } - - return null; - } - - public String getValue() { - return mValue; - } - - public String getDisplayValue() { - return mDisplay; - } - - public static int getIndex(NavigationMethod value) { - int i = 0; - for (NavigationMethod nav : values()) { - if (nav == value) { - return i; - } - - i++; - } - - return -1; - } - - public static NavigationMethod getByIndex(int index) { - int i = 0; - for (NavigationMethod value : values()) { - if (i == index) { - return value; - } - i++; - } - return null; - } - } - - public NavigationMethodQualifier() { - // pass - } - - public NavigationMethodQualifier(NavigationMethod value) { - mValue = value; - } - - public NavigationMethod getValue() { - return mValue; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Navigation"; - } - - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("navpad"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - NavigationMethod method = NavigationMethod.getEnum(value); - if (method != null) { - NavigationMethodQualifier qualifier = new NavigationMethodQualifier(); - qualifier.mValue = method; - config.setNavigationMethodQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof NavigationMethodQualifier) { - return mValue == ((NavigationMethodQualifier)qualifier).mValue; - } - - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - if (mValue != null) { - return mValue.getValue(); - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue.getDisplayValue(); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java deleted file mode 100644 index 7e30901..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Resource Qualifier for Mobile Network Code Pixel Density. - */ -public final class NetworkCodeQualifier extends ResourceQualifier { - /** Default pixel density value. This means the property is not set. */ - private final static int DEFAULT_CODE = -1; - - private final static Pattern sNetworkCodePattern = Pattern.compile("^mnc(\\d{1,3})$"); //$NON-NLS-1$ - - private int mCode = DEFAULT_CODE; - - public final static String NAME = "Mobile Network Code"; - - /** - * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, - * <code>null</code> is returned. - * @param segment the folder segment from which to create a qualifier. - * @return a new {@link CountryCodeQualifier} object or <code>null</code> - */ - public static NetworkCodeQualifier getQualifier(String segment) { - Matcher m = sNetworkCodePattern.matcher(segment); - if (m.matches()) { - String v = m.group(1); - - int code = -1; - try { - code = Integer.parseInt(v); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid number. - return null; - } - - NetworkCodeQualifier qualifier = new NetworkCodeQualifier(); - qualifier.mCode = code; - return qualifier; - } - - return null; - } - - /** - * Returns the folder name segment for the given value. This is equivalent to calling - * {@link #toString()} on a {@link NetworkCodeQualifier} object. - * @param code the value of the qualifier, as returned by {@link #getCode()}. - */ - public static String getFolderSegment(int code) { - if (code != DEFAULT_CODE && code >= 1 && code <= 999) { // code is 1-3 digit. - return String.format("mnc%1$d", code); //$NON-NLS-1$ - } - - return ""; //$NON-NLS-1$ - } - - public int getCode() { - return mCode; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Network Code"; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("mnc"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mCode != DEFAULT_CODE; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - Matcher m = sNetworkCodePattern.matcher(value); - if (m.matches()) { - String v = m.group(1); - - int code = -1; - try { - code = Integer.parseInt(v); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid number. - return false; - } - - NetworkCodeQualifier qualifier = new NetworkCodeQualifier(); - qualifier.mCode = code; - config.setNetworkCodeQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof NetworkCodeQualifier) { - return mCode == ((NetworkCodeQualifier)qualifier).mCode; - } - - return false; - } - - @Override - public int hashCode() { - return mCode; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - return getFolderSegment(mCode); - } - - @Override - public String getStringValue() { - if (mCode != DEFAULT_CODE) { - return String.format("MNC %1$d", mCode); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java deleted file mode 100644 index c47bb83..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Resource Qualifier for Screen Pixel Density. - */ -public final class PixelDensityQualifier extends ResourceQualifier { - /** Default pixel density value. This means the property is not set. */ - private final static int DEFAULT_DENSITY = -1; - - private final static Pattern sPixelDensityPattern = Pattern.compile("^(\\d+)dpi$");//$NON-NLS-1$ - - public static final String NAME = "Pixel Density"; - - private int mValue = DEFAULT_DENSITY; - - /** - * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, - * <code>null</code> is returned. - * @param folderSegment the folder segment from which to create a qualifier. - * @return a new {@link CountryCodeQualifier} object or <code>null</code> - */ - public static PixelDensityQualifier getQualifier(String folderSegment) { - Matcher m = sPixelDensityPattern.matcher(folderSegment); - if (m.matches()) { - String v = m.group(1); - - int density = -1; - try { - density = Integer.parseInt(v); - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid number. - return null; - } - - PixelDensityQualifier qualifier = new PixelDensityQualifier(); - qualifier.mValue = density; - - return qualifier; - } - return null; - } - - /** - * Returns the folder name segment for the given value. This is equivalent to calling - * {@link #toString()} on a {@link NetworkCodeQualifier} object. - * @param value the value of the qualifier, as returned by {@link #getValue()}. - */ - public static String getFolderSegment(int value) { - if (value != DEFAULT_DENSITY) { - return String.format("%1$ddpi", value); //$NON-NLS-1$ - } - - return ""; //$NON-NLS-1$ - } - - public int getValue() { - return mValue; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return NAME; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("dpi"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != DEFAULT_DENSITY; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - PixelDensityQualifier qualifier = getQualifier(value); - if (qualifier != null) { - config.setPixelDensityQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof PixelDensityQualifier) { - return mValue == ((PixelDensityQualifier)qualifier).mValue; - } - - return false; - } - - @Override - public int hashCode() { - return mValue; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - return getFolderSegment(mValue); - } - - @Override - public String getStringValue() { - if (mValue != DEFAULT_DENSITY) { - return String.format("%1$d dpi", mValue); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/RegionQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/RegionQualifier.java deleted file mode 100644 index dc4d5fa..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/RegionQualifier.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Resource Qualifier for Region. - */ -public final class RegionQualifier extends ResourceQualifier { - private final static Pattern sRegionPattern = Pattern.compile("^r([A-Z]{2})$"); //$NON-NLS-1$ - - public static final String NAME = "Region"; - - private String mValue; - - /** - * Creates and returns a qualifier from the given folder segment. If the segment is incorrect, - * <code>null</code> is returned. - * @param segment the folder segment from which to create a qualifier. - * @return a new {@link RegionQualifier} object or <code>null</code> - */ - public static RegionQualifier getQualifier(String segment) { - Matcher m = sRegionPattern.matcher(segment); - if (m.matches()) { - RegionQualifier qualifier = new RegionQualifier(); - qualifier.mValue = m.group(1); - - return qualifier; - } - return null; - } - - /** - * Returns the folder name segment for the given value. This is equivalent to calling - * {@link #toString()} on a {@link RegionQualifier} object. - * @param value the value of the qualifier, as returned by {@link #getValue()}. - */ - public static String getFolderSegment(String value) { - if (value != null) { - String segment = "r" + value.toUpperCase(); //$NON-NLS-1$ - if (sRegionPattern.matcher(segment).matches()) { - return segment; - } - } - - return ""; //$NON-NLS-1$ - } - - public String getValue() { - if (mValue != null) { - return mValue; - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return NAME; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("region"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - RegionQualifier qualifier = getQualifier(value); - if (qualifier != null) { - config.setRegionQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof RegionQualifier) { - if (mValue == null) { - return ((RegionQualifier)qualifier).mValue == null; - } - return mValue.equals(((RegionQualifier)qualifier).mValue); - } - - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - return getFolderSegment(mValue); - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue; - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ResourceQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ResourceQualifier.java deleted file mode 100644 index 0257afa..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ResourceQualifier.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import org.eclipse.swt.graphics.Image; - -/** - * Base class for resource qualifiers. - * <p/>The resource qualifier classes are designed as immutable. - */ -public abstract class ResourceQualifier implements Comparable<ResourceQualifier> { - - /** - * Returns the human readable name of the qualifier. - */ - public abstract String getName(); - - /** - * Returns a shorter human readable name for the qualifier. - * @see #getName() - */ - public abstract String getShortName(); - - /** - * Returns the icon for the qualifier. - */ - public abstract Image getIcon(); - - /** - * Returns whether the qualifier has a valid filter value. - */ - public abstract boolean isValid(); - - /** - * Check if the value is valid for this qualifier, and if so sets the value - * into a Folder Configuration. - * @param value The value to check and set. Must not be null. - * @param config The folder configuration to receive the value. Must not be null. - * @return true if the value was valid and was set. - */ - public abstract boolean checkAndSet(String value, FolderConfiguration config); - - /** - * Returns a string formated to be used in a folder name. - * <p/>This is declared as abstract to force children classes to implement it. - */ - @Override - public abstract String toString(); - - /** - * Returns a string formatted for display purpose. - */ - public abstract String getStringValue(); - - /** - * Returns <code>true</code> if both objects are equal. - * <p/>This is declared as abstract to force children classes to implement it. - */ - @Override - public abstract boolean equals(Object object); - - /** - * Returns a hash code value for the object. - * <p/>This is declared as abstract to force children classes to implement it. - */ - @Override - public abstract int hashCode(); - - public final int compareTo(ResourceQualifier o) { - return toString().compareTo(o.toString()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ScreenDimensionQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ScreenDimensionQualifier.java deleted file mode 100644 index a2cc789..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ScreenDimensionQualifier.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Resource Qualifier for Screen Dimension. - */ -public final class ScreenDimensionQualifier extends ResourceQualifier { - /** Default screen size value. This means the property is not set */ - final static int DEFAULT_SIZE = -1; - - private final static Pattern sDimensionPattern = Pattern.compile( - "^(\\d+)x(\\d+)$"); //$NON-NLS-1$ - - public static final String NAME = "Screen Dimension"; - - /** Screen size 1 value. This is not size X or Y because the folder name always - * contains the biggest size first. So if the qualifier is 400x200, size 1 will always be - * 400 but that'll be X in landscape and Y in portrait. - * Default value is <code>DEFAULT_SIZE</code> */ - private int mValue1 = DEFAULT_SIZE; - - /** Screen size 2 value. This is not size X or Y because the folder name always - * contains the biggest size first. So if the qualifier is 400x200, size 2 will always be - * 200 but that'll be Y in landscape and X in portrait. - * Default value is <code>DEFAULT_SIZE</code> */ - private int mValue2 = DEFAULT_SIZE; - - public int getValue1() { - return mValue1; - } - - public int getValue2() { - return mValue2; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Dimension"; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("dimension"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue1 != DEFAULT_SIZE && mValue2 != DEFAULT_SIZE; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - Matcher m = sDimensionPattern.matcher(value); - if (m.matches()) { - String d1 = m.group(1); - String d2 = m.group(2); - - ScreenDimensionQualifier qualifier = getQualifier(d1, d2); - if (qualifier != null) { - config.setScreenDimensionQualifier(qualifier); - return true; - } - } - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof ScreenDimensionQualifier) { - ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier; - return (mValue1 == q.mValue1 && mValue2 == q.mValue2); - } - - return false; - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - public static ScreenDimensionQualifier getQualifier(String size1, String size2) { - try { - int s1 = Integer.parseInt(size1); - int s2 = Integer.parseInt(size2); - - ScreenDimensionQualifier qualifier = new ScreenDimensionQualifier(); - - if (s1 > s2) { - qualifier.mValue1 = s1; - qualifier.mValue2 = s2; - } else { - qualifier.mValue1 = s2; - qualifier.mValue2 = s1; - } - - return qualifier; - } catch (NumberFormatException e) { - // looks like the string we extracted wasn't a valid number. - } - - return null; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - return String.format("%1$dx%2$d", mValue1, mValue2); //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue1 != -1 && mValue2 != -1) { - return String.format("%1$dx%2$d", mValue1, mValue2); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ScreenOrientationQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ScreenOrientationQualifier.java deleted file mode 100644 index e30930f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/ScreenOrientationQualifier.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - -/** - * Resource Qualifier for Screen Orientation. - */ -public final class ScreenOrientationQualifier extends ResourceQualifier { - - public static final String NAME = "Screen Orientation"; - - private ScreenOrientation mValue = null; - - /** - * Screen Orientation enum. - */ - public static enum ScreenOrientation { - PORTRAIT("port", "Portrait"), //$NON-NLS-1$ - LANDSCAPE("land", "Landscape"), //$NON-NLS-1$ - SQUARE("square", "Square"); //$NON-NLS-1$ - - private String mValue; - private String mDisplayValue; - - private ScreenOrientation(String value, String displayValue) { - mValue = value; - mDisplayValue = displayValue; - } - - /** - * Returns the enum for matching the provided qualifier value. - * @param value The qualifier value. - * @return the enum for the qualifier value or null if no matching was found. - */ - static ScreenOrientation getEnum(String value) { - for (ScreenOrientation orient : values()) { - if (orient.mValue.equals(value)) { - return orient; - } - } - - return null; - } - - public String getValue() { - return mValue; - } - - public String getDisplayValue() { - return mDisplayValue; - } - - public static int getIndex(ScreenOrientation orientation) { - int i = 0; - for (ScreenOrientation orient : values()) { - if (orient == orientation) { - return i; - } - - i++; - } - - return -1; - } - - public static ScreenOrientation getByIndex(int index) { - int i = 0; - for (ScreenOrientation orient : values()) { - if (i == index) { - return orient; - } - i++; - } - - return null; - } - } - - public ScreenOrientationQualifier() { - } - - public ScreenOrientationQualifier(ScreenOrientation value) { - mValue = value; - } - - public ScreenOrientation getValue() { - return mValue; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Orientation"; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("orientation"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - ScreenOrientation orientation = ScreenOrientation.getEnum(value); - if (orientation != null) { - ScreenOrientationQualifier qualifier = new ScreenOrientationQualifier(orientation); - config.setScreenOrientationQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof ScreenOrientationQualifier) { - return mValue == ((ScreenOrientationQualifier)qualifier).mValue; - } - - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - if (mValue != null) { - return mValue.getValue(); - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue.getDisplayValue(); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifier.java deleted file mode 100644 index de40138..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifier.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - - - - -/** - * Resource Qualifier for Text Input Method. - */ -public final class TextInputMethodQualifier extends ResourceQualifier { - - public static final String NAME = "Text Input Method"; - - private TextInputMethod mValue; - - /** - * Screen Orientation enum. - */ - public static enum TextInputMethod { - NOKEY("nokeys", "No Keys"), //$NON-NLS-1$ - QWERTY("qwerty", "Qwerty"), //$NON-NLS-1$ - TWELVEKEYS("12key", "12 Key"); //$NON-NLS-1$ - - private String mValue; - private String mDisplayValue; - - private TextInputMethod(String value, String displayValue) { - mValue = value; - mDisplayValue = displayValue; - } - - /** - * Returns the enum for matching the provided qualifier value. - * @param value The qualifier value. - * @return the enum for the qualifier value or null if no matching was found. - */ - static TextInputMethod getEnum(String value) { - for (TextInputMethod orient : values()) { - if (orient.mValue.equals(value)) { - return orient; - } - } - - return null; - } - - public String getValue() { - return mValue; - } - - public String getDisplayValue() { - return mDisplayValue; - } - - public static int getIndex(TextInputMethod value) { - int i = 0; - for (TextInputMethod input : values()) { - if (value == input) { - return i; - } - - i++; - } - - return -1; - } - - public static TextInputMethod getByIndex(int index) { - int i = 0; - for (TextInputMethod value : values()) { - if (i == index) { - return value; - } - i++; - } - return null; - } - } - - public TextInputMethodQualifier() { - // pass - } - - public TextInputMethodQualifier(TextInputMethod value) { - mValue = value; - } - - public TextInputMethod getValue() { - return mValue; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return "Text Input"; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("text_input"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - TextInputMethod method = TextInputMethod.getEnum(value); - if (method != null) { - TextInputMethodQualifier qualifier = new TextInputMethodQualifier(); - qualifier.mValue = method; - config.setTextInputMethodQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof TextInputMethodQualifier) { - return mValue == ((TextInputMethodQualifier)qualifier).mValue; - } - - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - if (mValue != null) { - return mValue.getValue(); - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue.getDisplayValue(); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/TouchScreenQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/TouchScreenQualifier.java deleted file mode 100644 index 2390e2c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/TouchScreenQualifier.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.configurations; - -import com.android.ide.eclipse.editors.IconFactory; - -import org.eclipse.swt.graphics.Image; - - -/** - * Resource Qualifier for Touch Screen type. - */ -public final class TouchScreenQualifier extends ResourceQualifier { - - public static final String NAME = "Touch Screen"; - - private TouchScreenType mValue; - - /** - * Screen Orientation enum. - */ - public static enum TouchScreenType { - NOTOUCH("notouch", "No Touch"), //$NON-NLS-1$ - STYLUS("stylus", "Stylus"), //$NON-NLS-1$ - FINGER("finger", "Finger"); //$NON-NLS-1$ - - private String mValue; - private String mDisplayValue; - - private TouchScreenType(String value, String displayValue) { - mValue = value; - mDisplayValue = displayValue; - } - - /** - * Returns the enum for matching the provided qualifier value. - * @param value The qualifier value. - * @return the enum for the qualifier value or null if no matching was found. - */ - static TouchScreenType getEnum(String value) { - for (TouchScreenType orient : values()) { - if (orient.mValue.equals(value)) { - return orient; - } - } - - return null; - } - - public String getValue() { - return mValue; - } - - public String getDisplayValue() { - return mDisplayValue; - } - - public static int getIndex(TouchScreenType touch) { - int i = 0; - for (TouchScreenType t : values()) { - if (t == touch) { - return i; - } - - i++; - } - - return -1; - } - - public static TouchScreenType getByIndex(int index) { - int i = 0; - for (TouchScreenType value : values()) { - if (i == index) { - return value; - } - i++; - } - - return null; - } - } - - public TouchScreenQualifier() { - // pass - } - - public TouchScreenQualifier(TouchScreenType touchValue) { - mValue = touchValue; - } - - public TouchScreenType getValue() { - return mValue; - } - - @Override - public String getName() { - return NAME; - } - - @Override - public String getShortName() { - return NAME; - } - - @Override - public Image getIcon() { - return IconFactory.getInstance().getIcon("touch"); //$NON-NLS-1$ - } - - @Override - public boolean isValid() { - return mValue != null; - } - - @Override - public boolean checkAndSet(String value, FolderConfiguration config) { - TouchScreenType type = TouchScreenType.getEnum(value); - if (type != null) { - TouchScreenQualifier qualifier = new TouchScreenQualifier(); - qualifier.mValue = type; - config.setTouchTypeQualifier(qualifier); - return true; - } - - return false; - } - - @Override - public boolean equals(Object qualifier) { - if (qualifier instanceof TouchScreenQualifier) { - return mValue == ((TouchScreenQualifier)qualifier).mValue; - } - return false; - } - - @Override - public int hashCode() { - if (mValue != null) { - return mValue.hashCode(); - } - - return 0; - } - - /** - * Returns the string used to represent this qualifier in the folder name. - */ - @Override - public String toString() { - if (mValue != null) { - return mValue.getValue(); - } - - return ""; //$NON-NLS-1$ - } - - @Override - public String getStringValue() { - if (mValue != null) { - return mValue.getDisplayValue(); - } - - return ""; //$NON-NLS-1$ - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ColorValueDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ColorValueDescriptor.java deleted file mode 100644 index 92288ba..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ColorValueDescriptor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.descriptors; - -import com.android.ide.eclipse.editors.descriptors.TextValueDescriptor; -import com.android.ide.eclipse.editors.resources.uimodel.UiColorValueNode; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiResourceAttributeNode; - -/** - * Describes a Color XML element value displayed by an {@link UiColorValueNode}. - */ -public final class ColorValueDescriptor extends TextValueDescriptor { - - public ColorValueDescriptor(String uiName, String tooltip) { - super(uiName, tooltip); - } - - /** - * @return A new {@link UiResourceAttributeNode} linked to this theme descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiColorValueNode(this, uiParent); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ItemElementDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ItemElementDescriptor.java deleted file mode 100644 index bf83d52..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ItemElementDescriptor.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.descriptors; - -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.resources.uimodel.UiItemElementNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * {@link ItemElementDescriptor} is a special version of {@link ElementDescriptor} that - * uses a specialized {@link UiItemElementNode} for display. - */ -public class ItemElementDescriptor extends ElementDescriptor { - - /** - * Constructs a new {@link ItemElementDescriptor} based on its XML name, UI name, - * tooltip, SDK url, attributes list, children list and mandatory. - * - * @param xml_name The XML element node name. Case sensitive. - * @param ui_name The XML element name for the user interface, typically capitalized. - * @param tooltip An optional tooltip. Can be null or empty. - * @param sdk_url An optional SKD URL. Can be null or empty. - * @param attributes The list of allowed attributes. Can be null or empty. - * @param children The list of allowed children. Can be null or empty. - * @param mandatory Whether this node must always exist (even for empty models). A mandatory - * UI node is never deleted and it may lack an actual XML node attached. A non-mandatory - * UI node MUST have an XML node attached and it will cease to exist when the XML node - * ceases to exist. - */ - public ItemElementDescriptor(String xml_name, String ui_name, - String tooltip, String sdk_url, AttributeDescriptor[] attributes, - ElementDescriptor[] children, boolean mandatory) { - super(xml_name, ui_name, tooltip, sdk_url, attributes, children, mandatory); - } - - @Override - public UiElementNode createUiNode() { - return new UiItemElementNode(this); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ResourcesDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ResourcesDescriptors.java deleted file mode 100644 index 1075897..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/descriptors/ResourcesDescriptors.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.descriptors; - -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.FlagAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.ListAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextValueDescriptor; - - -/** - * Complete description of the structure for resources XML files (under res/values/) - */ -public class ResourcesDescriptors implements IDescriptorProvider { - - // Public attributes names, attributes descriptors and elements descriptors - - public static final String ROOT_ELEMENT = "resources"; //$NON-NLS-1$ - - public static final String NAME_ATTR = "name"; //$NON-NLS-1$ - public static final String TYPE_ATTR = "type"; //$NON-NLS-1$ - - private static final ResourcesDescriptors sThis = new ResourcesDescriptors(); - - /** The {@link ElementDescriptor} for the root Resources element. */ - public final ElementDescriptor mResourcesElement; - - public static ResourcesDescriptors getInstance() { - return sThis; - } - - /* - * @see com.android.ide.eclipse.editors.descriptors.IDescriptorProvider#getRootElementDescriptors() - */ - public ElementDescriptor[] getRootElementDescriptors() { - return new ElementDescriptor[] { mResourcesElement }; - } - - public ElementDescriptor getDescriptor() { - return mResourcesElement; - } - - public ElementDescriptor getElementDescriptor() { - return mResourcesElement; - } - - private ResourcesDescriptors() { - - // Common attributes used in many placed - - // Elements - - ElementDescriptor color_element = new ElementDescriptor( - "color", //$NON-NLS-1$ - "Color", - "A @color@ value specifies an RGB value with an alpha channel, which can be used in various places such as specifying a solid color for a Drawable or the color to use for text. It always begins with a # character and then is followed by the alpha-red-green-blue information in one of the following formats: #RGB, #ARGB, #RRGGBB or #AARRGGBB.", - "http://code.google.com/android/reference/available-resources.html#colorvals", //$NON-NLS-1$ - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this color."), - new ColorValueDescriptor( - "Value*", - "A mandatory color value.") - }, - null, // no child nodes - false /* not mandatory */); - - ElementDescriptor string_element = new ElementDescriptor( - "string", //$NON-NLS-1$ - "String", - "@Strings@, with optional simple formatting, can be stored and retrieved as resources. You can add formatting to your string by using three standard HTML tags: b, i, and u. If you use an apostrophe or a quote in your string, you must either escape it or enclose the whole string in the other kind of enclosing quotes.", - "http://code.google.com/android/reference/available-resources.html#stringresources", //$NON-NLS-1$ - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this string."), - new TextValueDescriptor( - "Value*", - "A mandatory string value.") - }, - null, // no child nodes - false /* not mandatory */); - - ElementDescriptor item_element = new ItemElementDescriptor( - "item", //$NON-NLS-1$ - "Item", - null, // TODO find javadoc - null, // TODO find link to javadoc - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this resource."), - new ListAttributeDescriptor(TYPE_ATTR, - "Type*", - null /* nsUri */, - "The mandatory type of this resource.", - ResourceType.getNames() - ), - new FlagAttributeDescriptor("format", - "Format", - null /* nsUri */, - "The optional format of this resource.", - new String[] { - "boolean", //$NON-NLS-1$ - "color", //$NON-NLS-1$ - "dimension", //$NON-NLS-1$ - "float", //$NON-NLS-1$ - "fraction", //$NON-NLS-1$ - "integer", //$NON-NLS-1$ - "reference", //$NON-NLS-1$ - "string" //$NON-NLS-1$ - }), - new TextValueDescriptor( - "Value", - "A standard string, hex color value, or reference to any other resource type.") - }, - null, // no child nodes - false /* not mandatory */); - - ElementDescriptor drawable_element = new ElementDescriptor( - "drawable", //$NON-NLS-1$ - "Drawable", - "A @drawable@ defines a rectangle of color. Android accepts color values written in various web-style formats -- a hexadecimal constant in any of the following forms: #RGB, #ARGB, #RRGGBB, #AARRGGBB. Zero in the alpha channel means transparent. The default value is opaque.", - "http://code.google.com/android/reference/available-resources.html#colordrawableresources", //$NON-NLS-1$ - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this drawable."), - new TextValueDescriptor( - "Value*", - "A mandatory color value in the form #RGB, #ARGB, #RRGGBB or #AARRGGBB.") - }, - null, // no child nodes - false /* not mandatory */); - - ElementDescriptor dimen_element = new ElementDescriptor( - "dimen", //$NON-NLS-1$ - "Dimension", - "You can create common dimensions to use for various screen elements by defining @dimension@ values in XML. A dimension resource is a number followed by a unit of measurement. Supported units are px (pixels), in (inches), mm (millimeters), pt (points at 72 DPI), dp (density-independent pixels) and sp (scale-independent pixels)", - "http://code.google.com/android/reference/available-resources.html#dimension", //$NON-NLS-1$ - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this dimension."), - new TextValueDescriptor( - "Value*", - "A mandatory dimension value is a number followed by a unit of measurement. For example: 10px, 2in, 5sp.") - }, - null, // no child nodes - false /* not mandatory */); - - ElementDescriptor style_element = new ElementDescriptor( - "style", //$NON-NLS-1$ - "Style/Theme", - "Both @styles and themes@ are defined in a style block containing one or more string or numerical values (typically color values), or references to other resources (drawables and so on).", - "http://code.google.com/android/reference/available-resources.html#stylesandthemes", //$NON-NLS-1$ - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this theme."), - new TextAttributeDescriptor("parent", // $NON-NLS-1$ - "Parent", - null /* nsUri */, - "An optional parent theme. All values from the specified theme will be inherited into this theme. Any values with identical names that you specify will override inherited values."), - }, - new ElementDescriptor[] { - new ElementDescriptor( - "item", //$NON-NLS-1$ - "Item", - "A value to use in this @theme@. It can be a standard string, a hex color value, or a reference to any other resource type.", - "http://code.google.com/android/reference/available-resources.html#stylesandthemes", //$NON-NLS-1$ - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this item."), - new TextValueDescriptor( - "Value*", - "A mandatory standard string, hex color value, or reference to any other resource type.") - }, - null, // no child nodes - false /* not mandatory */) - }, - false /* not mandatory */); - - ElementDescriptor string_array_element = new ElementDescriptor( - "string-array", //$NON-NLS-1$ - "String Array", - "An array of strings. Strings are added as underlying item elements to the array.", - null, // tooltips - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this string array."), - }, - new ElementDescriptor[] { - new ElementDescriptor( - "item", //$NON-NLS-1$ - "Item", - "A string value to use in this string array.", - null, // tooltip - new AttributeDescriptor[] { - new TextValueDescriptor( - "Value*", - "A mandatory string.") - }, - null, // no child nodes - false /* not mandatory */) - }, - false /* not mandatory */); - - ElementDescriptor integer_array_element = new ElementDescriptor( - "integer-array", //$NON-NLS-1$ - "Integer Array", - "An array of integers. Integers are added as underlying item elements to the array.", - null, // tooltips - new AttributeDescriptor[] { - new TextAttributeDescriptor(NAME_ATTR, - "Name*", - null /* nsUri */, - "The mandatory name used in referring to this integer array."), - }, - new ElementDescriptor[] { - new ElementDescriptor( - "item", //$NON-NLS-1$ - "Item", - "An integer value to use in this integer array.", - null, // tooltip - new AttributeDescriptor[] { - new TextValueDescriptor( - "Value*", - "A mandatory integer.") - }, - null, // no child nodes - false /* not mandatory */) - }, - false /* not mandatory */); - - mResourcesElement = new ElementDescriptor( - ROOT_ELEMENT, - "Resources", - null, - "http://code.google.com/android/reference/available-resources.html", //$NON-NLS-1$ - null, // no attributes - new ElementDescriptor[] { - string_element, - color_element, - dimen_element, - drawable_element, - style_element, - item_element, - string_array_element, - integer_array_element, - }, - true /* mandatory */); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java deleted file mode 100644 index d1d8891..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.explorer; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.resources.manager.ProjectResourceItem; -import com.android.ide.eclipse.editors.resources.manager.ProjectResources; -import com.android.ide.eclipse.editors.resources.manager.ResourceFile; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IResourceEventListener; -import com.android.ide.eclipse.editors.wizards.ResourceContentProvider; -import com.android.ide.eclipse.editors.wizards.ResourceLabelProvider; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTException; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.ISelectionListener; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.part.ViewPart; - -import java.util.Iterator; - -/** - * Resource Explorer View. - * <p/> - * This contains a basic Tree view, and uses a TreeViewer to handle the data. - * <p/> - * The view listener to change in selection in the workbench, and update to show the resource - * of the project of the current selected item (either item in the package explorer, or of the - * current editor). - * - * @see ResourceContentProvider - */ -public class ResourceExplorerView extends ViewPart implements ISelectionListener, - IResourceEventListener { - - // Note: keep using the obsolete AndroidConstants.EDITORS_NAMESPACE (which used - // to be the Editors Plugin ID) to keep existing preferences functional. - private final static String PREFS_COLUMN_RES = - AndroidConstants.EDITORS_NAMESPACE + "ResourceExplorer.Col1"; //$NON-NLS-1$ - private final static String PREFS_COLUMN_2 = - AndroidConstants.EDITORS_NAMESPACE + "ResourceExplorer.Col2"; //$NON-NLS-1$ - - private Tree mTree; - private TreeViewer mTreeViewer; - - private IProject mCurrentProject; - - public ResourceExplorerView() { - } - - @Override - public void createPartControl(Composite parent) { - mTree = new Tree(parent, SWT.SINGLE | SWT.VIRTUAL); - mTree.setLayoutData(new GridData(GridData.FILL_BOTH)); - mTree.setHeaderVisible(true); - mTree.setLinesVisible(true); - - final IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - - // create 2 columns. The main one with the resources, and an "info" column. - createTreeColumn(mTree, "Resources", SWT.LEFT, - "abcdefghijklmnopqrstuvwxz", -1, PREFS_COLUMN_RES, store); //$NON-NLS-1$ - createTreeColumn(mTree, "Info", SWT.LEFT, - "0123456789", -1, PREFS_COLUMN_2, store); //$NON-NLS-1$ - - // create the jface wrapper - mTreeViewer = new TreeViewer(mTree); - - mTreeViewer.setContentProvider(new ResourceContentProvider(true /* fullLevels */)); - mTreeViewer.setLabelProvider(new ResourceLabelProvider()); - - // listen to selection change in the workbench. - IWorkbenchPage page = getSite().getPage(); - - page.addSelectionListener(this); - - // init with current selection - selectionChanged(getSite().getPart(), page.getSelection()); - - // add support for double click. - mTreeViewer.addDoubleClickListener(new IDoubleClickListener() { - public void doubleClick(DoubleClickEvent event) { - ISelection sel = event.getSelection(); - - if (sel instanceof IStructuredSelection) { - IStructuredSelection selection = (IStructuredSelection) sel; - - if (selection.size() == 1) { - Object element = selection.getFirstElement(); - - // if it's a resourceFile, we directly open it. - if (element instanceof ResourceFile) { - try { - IDE.openEditor(getSite().getWorkbenchWindow().getActivePage(), - ((ResourceFile)element).getFile().getIFile()); - } catch (PartInitException e) { - } - } else if (element instanceof ProjectResourceItem) { - // if it's a ResourceItem, we open the first file, but only if - // there's no alternate files. - ProjectResourceItem item = (ProjectResourceItem)element; - - if (item.isEditableDirectly()) { - ResourceFile[] files = item.getSourceFileArray(); - if (files[0] != null) { - try { - IDE.openEditor( - getSite().getWorkbenchWindow().getActivePage(), - files[0].getFile().getIFile()); - } catch (PartInitException e) { - } - } - } - } - } - } - } - }); - - // set up the resource manager to send us resource change notification - AdtPlugin.getDefault().getResourceMonitor().addResourceEventListener(this); - } - - @Override - public void dispose() { - AdtPlugin.getDefault().getResourceMonitor().removeResourceEventListener(this); - - super.dispose(); - } - - @Override - public void setFocus() { - mTree.setFocus(); - } - - /** - * Processes a new selection. - */ - public void selectionChanged(IWorkbenchPart part, ISelection selection) { - // first we test if the part is an editor. - if (part instanceof IEditorPart) { - // if it is, we check if it's a file editor. - IEditorInput input = ((IEditorPart)part).getEditorInput(); - - if (input instanceof IFileEditorInput) { - // from the file editor we can get the IFile object, and from it, the IProject. - IFile file = ((IFileEditorInput)input).getFile(); - - // get the file project - IProject project = file.getProject(); - - handleProjectSelection(project); - } - } else if (selection instanceof IStructuredSelection) { - // if it's not an editor, we look for structured selection. - for (Iterator<?> it = ((IStructuredSelection) selection).iterator(); - it.hasNext();) { - Object element = it.next(); - IProject project = null; - - // if we are in the navigator or package explorer, the selection could contain a - // IResource object. - if (element instanceof IResource) { - project = ((IResource) element).getProject(); - } else if (element instanceof IJavaElement) { - // if we are in the package explorer on a java element, we handle that too. - IJavaElement javaElement = (IJavaElement)element; - IJavaProject javaProject = javaElement.getJavaProject(); - if (javaProject != null) { - project = javaProject.getProject(); - } - } else if (element instanceof IAdaptable) { - // finally we try to get a project object from IAdaptable. - project = (IProject) ((IAdaptable) element) - .getAdapter(IProject.class); - } - - // if we found a project, handle it, and return. - if (project != null) { - if (handleProjectSelection(project)) { - return; - } - } - } - } - } - - /** - * Handles a project selection. - * @param project the new selected project - * @return true if the project could be processed. - */ - private boolean handleProjectSelection(IProject project) { - try { - // if it's an android project, then we get its resources, and feed them - // to the tree viewer. - if (project.hasNature(AndroidConstants.NATURE)) { - if (mCurrentProject != project) { - ProjectResources projRes = ResourceManager.getInstance().getProjectResources( - project); - if (projRes != null) { - mTreeViewer.setInput(projRes); - mCurrentProject = project; - return true; - } - } - } - } catch (CoreException e) { - } - - return false; - } - - /** - * Create a TreeColumn with the specified parameters. If a - * <code>PreferenceStore</code> object and a preference entry name String - * object are provided then the column will listen to change in its width - * and update the preference store accordingly. - * - * @param parent The Table parent object - * @param header The header string - * @param style The column style - * @param sample_text A sample text to figure out column width if preference - * value is missing - * @param fixedSize a fixed size. If != -1 the column is non resizable - * @param pref_name The preference entry name for column width - * @param prefs The preference store - */ - public void createTreeColumn(Tree parent, String header, int style, - String sample_text, int fixedSize, final String pref_name, - final IPreferenceStore prefs) { - - // create the column - TreeColumn col = new TreeColumn(parent, style); - - if (fixedSize != -1) { - col.setWidth(fixedSize); - col.setResizable(false); - } else { - // if there is no pref store or the entry is missing, we use the sample - // text and pack the column. - // Otherwise we just read the width from the prefs and apply it. - if (prefs == null || prefs.contains(pref_name) == false) { - col.setText(sample_text); - col.pack(); - - // init the prefs store with the current value - if (prefs != null) { - prefs.setValue(pref_name, col.getWidth()); - } - } else { - col.setWidth(prefs.getInt(pref_name)); - } - - // if there is a pref store and a pref entry name, then we setup a - // listener to catch column resize to put the new width value into the store. - if (prefs != null && pref_name != null) { - col.addControlListener(new ControlListener() { - public void controlMoved(ControlEvent e) { - } - - public void controlResized(ControlEvent e) { - // get the new width - int w = ((TreeColumn)e.widget).getWidth(); - - // store in pref store - prefs.setValue(pref_name, w); - } - }); - } - } - - // set the header - col.setText(header); - } - - /** - * Processes a start in a resource event change. - */ - public void resourceChangeEventStart() { - // pass - } - - /** - * Processes the end of a resource change event. - */ - public void resourceChangeEventEnd() { - try { - mTree.getDisplay().asyncExec(new Runnable() { - public void run() { - if (mTree.isDisposed() == false) { - mTreeViewer.refresh(); - } - } - }); - } catch (SWTException e) { - // display is disposed. nothing to do. - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java deleted file mode 100644 index 455c825..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.AndroidManifestHelper; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.runtime.CoreException; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.Map; - -/** - * A monitor for the compiled resources. This only monitors changes in the resources of type - * {@link ResourceType#ID}. - */ -public final class CompiledResourcesMonitor implements IFileListener, IProjectListener { - - private final static CompiledResourcesMonitor sThis = new CompiledResourcesMonitor(); - - /** - * Sets up the monitoring system. - * @param monitor The main Resource Monitor. - */ - public static void setupMonitor(ResourceMonitor monitor) { - monitor.addFileListener(sThis, IResourceDelta.ADDED | IResourceDelta.CHANGED); - monitor.addProjectListener(sThis); - } - - /** - * private constructor to prevent construction. - */ - private CompiledResourcesMonitor() { - } - - - /* (non-Javadoc) - * Sent when a file changed : if the file is the R class, then it is parsed again to update - * the internal data. - * - * @param file The file that changed. - * @param markerDeltas The marker deltas for the file. - * @param kind The change kind. This is equivalent to - * {@link IResourceDelta#accept(IResourceDeltaVisitor)} - * - * @see IFileListener#fileChanged - */ - public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { - if (file.getName().equals(AndroidConstants.FN_COMPILED_RESOURCE_CLASS)) { - loadAndParseRClass(file.getProject()); - } - } - - /** - * Processes project close event. - */ - public void projectClosed(IProject project) { - // the ProjectResources object will be removed by the ResourceManager. - } - - /** - * Processes project delete event. - */ - public void projectDeleted(IProject project) { - // the ProjectResources object will be removed by the ResourceManager. - } - - /** - * Processes project open event. - */ - public void projectOpened(IProject project) { - // when the project is opened, we get an ADDED event for each file, so we don't - // need to do anything here. - } - - /** - * Processes existing project at init time. - */ - public void projectOpenedWithWorkspace(IProject project) { - try { - // check this is an android project - if (project.hasNature(AndroidConstants.NATURE)) { - loadAndParseRClass(project); - } - } catch (CoreException e) { - // pass - } - } - - private void loadAndParseRClass(IProject project) { - try { - // first check there's a ProjectResources to store the content - ProjectResources projectResources = ResourceManager.getInstance().getProjectResources( - project); - - if (projectResources != null) { - // create the classname - String className = getRClassName(project); - - // create a temporary class loader to load it. - ProjectClassLoader loader = new ProjectClassLoader(null /* parentClassLoader */, - project); - - try { - Class<?> clazz = loader.loadClass(className); - - if (clazz != null) { - // create the maps to store the result of the parsing - Map<String, Map<String, Integer>> resourceValueMap = - new HashMap<String, Map<String, Integer>>(); - Map<Integer, String[]> genericValueToNameMap = - new HashMap<Integer, String[]>(); - Map<IntArrayWrapper, String> styleableValueToNameMap = - new HashMap<IntArrayWrapper, String>(); - - // parse the class - if (parseClass(clazz, genericValueToNameMap, styleableValueToNameMap, - resourceValueMap)) { - // now we associate the maps to the project. - projectResources.setCompiledResources(genericValueToNameMap, - styleableValueToNameMap, resourceValueMap); - } - } - } catch (Error e) { - // Log this error with the class name we're trying to load and abort. - AdtPlugin.log(e, "loadAndParseRClass failed to find class %1$s", className); //$NON-NLS-1$ - } - } - } catch (ClassNotFoundException e) { - // pass - } - } - - /** - * Parses a R class, and fills maps. - * @param rClass the class to parse - * @param genericValueToNameMap - * @param styleableValueToNameMap - * @param resourceValueMap - * @return True if we managed to parse the R class. - */ - private boolean parseClass(Class<?> rClass, Map<Integer, String[]> genericValueToNameMap, - Map<IntArrayWrapper, String> styleableValueToNameMap, Map<String, - Map<String, Integer>> resourceValueMap) { - try { - for (Class<?> inner : rClass.getDeclaredClasses()) { - String resType = inner.getSimpleName(); - - Map<String, Integer> fullMap = new HashMap<String, Integer>(); - resourceValueMap.put(resType, fullMap); - - for (Field f : inner.getDeclaredFields()) { - // only process static final fields. - int modifiers = f.getModifiers(); - if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { - Class<?> type = f.getType(); - if (type.isArray() && type.getComponentType() == int.class) { - // if the object is an int[] we put it in the styleable map - styleableValueToNameMap.put(new IntArrayWrapper((int[]) f.get(null)), - f.getName()); - } else if (type == int.class) { - Integer value = (Integer) f.get(null); - genericValueToNameMap.put(value, new String[] { f.getName(), resType }); - fullMap.put(f.getName(), value); - } else { - assert false; - } - } - } - } - - return true; - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { - } - return false; - } - - private String getRClassName(IProject project) { - // create the classname - AndroidManifestHelper manifest = new AndroidManifestHelper(project); - String javaPackage = manifest.getPackageName(); - - return javaPackage + ".R"; //$NON-NLS-1$ - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ConfigurableResourceItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ConfigurableResourceItem.java deleted file mode 100644 index 57c17fc..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ConfigurableResourceItem.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -/** - * Represents a resource item that can exist in multiple "alternate" versions. - */ -public class ConfigurableResourceItem extends ProjectResourceItem { - - /** - * Constructs a new Resource Item. - * @param name the name of the resource as it appears in the XML and R.java files. - */ - public ConfigurableResourceItem(String name) { - super(name); - } - - /** - * Returns if the resource item has at least one non-default configuration. - */ - public boolean hasAlternates() { - for (ResourceFile file : mFiles) { - if (file.getFolder().getConfiguration().isDefault() == false) { - return true; - } - } - - return false; - } - - /** - * Returns whether the resource has a default version, with no qualifier. - */ - public boolean hasDefault() { - for (ResourceFile file : mFiles) { - if (file.getFolder().getConfiguration().isDefault()) { - return true; - } - } - - // We only want to return false if there's no default and more than 0 items. - return (mFiles.size() == 0); - } - - /** - * Returns the number of alternate versions of this resource. - */ - public int getAlternateCount() { - int count = 0; - for (ResourceFile file : mFiles) { - if (file.getFolder().getConfiguration().isDefault() == false) { - count++; - } - } - - return count; - } - - /* - * (non-Javadoc) - * Returns whether the item can be edited directly (ie it does not have alternate versions). - */ - @Override - public boolean isEditableDirectly() { - return hasAlternates() == false; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/FolderTypeRelationship.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/FolderTypeRelationship.java deleted file mode 100644 index a9f80bd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/FolderTypeRelationship.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.ResourceType; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -/** - * This class gives access to the bi directional relationship between {@link ResourceType} and - * {@link ResourceFolderType}. - */ -public final class FolderTypeRelationship { - - private final static HashMap<ResourceType, ResourceFolderType[]> mTypeToFolderMap = - new HashMap<ResourceType, ResourceFolderType[]>(); - - private final static HashMap<ResourceFolderType, ResourceType[]> mFolderToTypeMap = - new HashMap<ResourceFolderType, ResourceType[]>(); - - // generate the relationships. - static { - HashMap<ResourceType, List<ResourceFolderType>> typeToFolderMap = - new HashMap<ResourceType, List<ResourceFolderType>>(); - - HashMap<ResourceFolderType, List<ResourceType>> folderToTypeMap = - new HashMap<ResourceFolderType, List<ResourceType>>(); - - add(ResourceType.ANIM, ResourceFolderType.ANIM, typeToFolderMap, folderToTypeMap); - add(ResourceType.ARRAY, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.COLOR, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.COLOR, ResourceFolderType.COLOR, typeToFolderMap, folderToTypeMap); - add(ResourceType.DIMEN, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.DRAWABLE, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.DRAWABLE, ResourceFolderType.DRAWABLE, typeToFolderMap, folderToTypeMap); - add(ResourceType.ID, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.LAYOUT, ResourceFolderType.LAYOUT, typeToFolderMap, folderToTypeMap); - add(ResourceType.MENU, ResourceFolderType.MENU, typeToFolderMap, folderToTypeMap); - add(ResourceType.RAW, ResourceFolderType.RAW, typeToFolderMap, folderToTypeMap); - add(ResourceType.STRING, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.STYLE, ResourceFolderType.VALUES, typeToFolderMap, folderToTypeMap); - add(ResourceType.XML, ResourceFolderType.XML, typeToFolderMap, folderToTypeMap); - - optimize(typeToFolderMap, folderToTypeMap); - } - - /** - * Returns a list of {@link ResourceType}s that can be generated from files inside a folder - * of the specified type. - * @param folderType The folder type. - * @return an array of {@link ResourceType} - */ - public static ResourceType[] getRelatedResourceTypes(ResourceFolderType folderType) { - ResourceType[] array = mFolderToTypeMap.get(folderType); - if (array != null) { - return array; - } - return new ResourceType[0]; - } - - /** - * Returns a list of {@link ResourceFolderType} that can contain files generating resources - * of the specified type. - * @param resType the type of resource. - * @return an array of {@link ResourceFolderType} - */ - public static ResourceFolderType[] getRelatedFolders(ResourceType resType) { - ResourceFolderType[] array = mTypeToFolderMap.get(resType); - if (array != null) { - return array; - } - return new ResourceFolderType[0]; - } - - /** - * Returns true if the {@link ResourceType} and the {@link ResourceFolderType} values match. - * @param resType the resource type. - * @param folderType the folder type. - * @return true if files inside the folder of the specified {@link ResourceFolderType} - * could generate a resource of the specified {@link ResourceType} - */ - public static boolean match(ResourceType resType, ResourceFolderType folderType) { - ResourceFolderType[] array = mTypeToFolderMap.get(resType); - - if (array != null && array.length > 0) { - for (ResourceFolderType fType : array) { - if (fType == folderType) { - return true; - } - } - } - - return false; - } - - /** - * Adds a {@link ResourceType} - {@link ResourceFolderType} relationship. this indicates that - * a file in the folder can generate a resource of the specified type. - * @param type The resourceType - * @param folder The {@link ResourceFolderType} - * @param folderToTypeMap - * @param typeToFolderMap - */ - private static void add(ResourceType type, ResourceFolderType folder, - HashMap<ResourceType, List<ResourceFolderType>> typeToFolderMap, - HashMap<ResourceFolderType, List<ResourceType>> folderToTypeMap) { - // first we add the folder to the list associated with the type. - List<ResourceFolderType> folderList = typeToFolderMap.get(type); - if (folderList == null) { - folderList = new ArrayList<ResourceFolderType>(); - typeToFolderMap.put(type, folderList); - } - if (folderList.indexOf(folder) == -1) { - folderList.add(folder); - } - - // now we add the type to the list associated with the folder. - List<ResourceType> typeList = folderToTypeMap.get(folder); - if (typeList == null) { - typeList = new ArrayList<ResourceType>(); - folderToTypeMap.put(folder, typeList); - } - if (typeList.indexOf(type) == -1) { - typeList.add(type); - } - } - - /** - * Optimize the map to contains array instead of lists (since the api returns arrays) - * @param typeToFolderMap - * @param folderToTypeMap - */ - private static void optimize(HashMap<ResourceType, List<ResourceFolderType>> typeToFolderMap, - HashMap<ResourceFolderType, List<ResourceType>> folderToTypeMap) { - Set<ResourceType> types = typeToFolderMap.keySet(); - for (ResourceType type : types) { - List<ResourceFolderType> list = typeToFolderMap.get(type); - mTypeToFolderMap.put(type, list.toArray(new ResourceFolderType[list.size()])); - } - - Set<ResourceFolderType> folders = folderToTypeMap.keySet(); - for (ResourceFolderType folder : folders) { - List<ResourceType> list = folderToTypeMap.get(folder); - mFolderToTypeMap.put(folder, list.toArray(new ResourceType[list.size()])); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/IdResourceItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/IdResourceItem.java deleted file mode 100644 index 552aec9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/IdResourceItem.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.IIdResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; - -/** - * Represents a resource item of type {@link ResourceType#ID} - */ -public class IdResourceItem extends ProjectResourceItem implements IIdResourceItem { - - private final boolean mIsDeclaredInline; - - /** - * Constructs a new ResourceItem. - * @param name the name of the resource as it appears in the XML and R.java files. - * @param isDeclaredInline Whether this id was declared inline. - */ - IdResourceItem(String name, boolean isDeclaredInline) { - super(name); - mIsDeclaredInline = isDeclaredInline; - } - - /* - * (non-Javadoc) - * Returns whether the ID resource has been declared inline inside another resource XML file. - */ - public boolean isDeclaredInline() { - return mIsDeclaredInline; - } - - /* (non-Javadoc) - * Returns whether the item can be edited (ie, the id was not declared inline). - */ - @Override - public boolean isEditableDirectly() { - return !mIsDeclaredInline; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/IntArrayWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/IntArrayWrapper.java deleted file mode 100644 index 25eb112..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/IntArrayWrapper.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager; - -import java.util.Arrays; - - -/** - * Wrapper around a int[] to provide hashCode/equals support. - */ -public final class IntArrayWrapper { - - private int[] mData; - - public IntArrayWrapper(int[] data) { - mData = data; - } - - public void set(int[] data) { - mData = data; - } - - @Override - public int hashCode() { - return Arrays.hashCode(mData); - } - - @Override - public boolean equals(Object obj) { - if (getClass().equals(obj.getClass())) { - return Arrays.equals(mData, ((IntArrayWrapper)obj).mData); - } - - return super.equals(obj); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java deleted file mode 100644 index 3812791..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFile; -import com.android.layoutlib.api.IResourceValue; -import com.android.layoutlib.utils.ResourceValue; -import com.android.layoutlib.utils.ValueResourceParser; -import com.android.layoutlib.utils.ValueResourceParser.IValueResourceRepository; - -import org.eclipse.core.runtime.CoreException; -import org.xml.sax.SAXException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Set; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Represents a resource file able to declare multiple resources, which could be of - * different {@link ResourceType}. - * <p/> - * This is typically an XML file inside res/values. - */ -public final class MultiResourceFile extends ResourceFile implements IValueResourceRepository { - - private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance(); - - private final HashMap<ResourceType, HashMap<String, ResourceValue>> mResourceItems = - new HashMap<ResourceType, HashMap<String, ResourceValue>>(); - - public MultiResourceFile(IAbstractFile file, ResourceFolder folder) { - super(file, folder); - } - - @Override - public ResourceType[] getResourceTypes() { - update(); - - Set<ResourceType> keys = mResourceItems.keySet(); - - return keys.toArray(new ResourceType[keys.size()]); - } - - @Override - public boolean hasResources(ResourceType type) { - update(); - - HashMap<String, ResourceValue> list = mResourceItems.get(type); - return (list != null && list.size() > 0); - } - - @Override - public Collection<ProjectResourceItem> getResources(ResourceType type, - ProjectResources projectResources) { - update(); - - HashMap<String, ResourceValue> list = mResourceItems.get(type); - - ArrayList<ProjectResourceItem> items = new ArrayList<ProjectResourceItem>(); - - if (list != null) { - Collection<ResourceValue> values = list.values(); - for (ResourceValue res : values) { - ProjectResourceItem item = projectResources.findResourceItem(type, res.getName()); - - if (item == null) { - if (type == ResourceType.ID) { - item = new IdResourceItem(res.getName(), false /* isDeclaredInline */); - } else { - item = new ConfigurableResourceItem(res.getName()); - } - items.add(item); - } - - item.add(this); - } - } - - return items; - } - - /** - * Updates the Resource items if necessary. - */ - private void update() { - if (isTouched() == true) { - // reset current content. - mResourceItems.clear(); - - // need to parse the file and find the content. - parseFile(); - - resetTouch(); - } - } - - /** - * Parses the file and creates a list of {@link ResourceType}. - */ - private void parseFile() { - try { - SAXParser parser = sParserFactory.newSAXParser(); - parser.parse(getFile().getContents(), new ValueResourceParser(this, isFramework())); - } catch (ParserConfigurationException e) { - } catch (SAXException e) { - } catch (IOException e) { - } catch (CoreException e) { - } - } - - /** - * Adds a resource item to the list - * @param resType The type of the resource - * @param value The value of the resource. - */ - public void addResourceValue(String resType, ResourceValue value) { - ResourceType type = ResourceType.getEnum(resType); - if (type != null) { - HashMap<String, ResourceValue> list = mResourceItems.get(type); - - // if the list does not exist, create it. - if (list == null) { - list = new HashMap<String, ResourceValue>(); - mResourceItems.put(type, list); - } else { - // look for a possible value already existing. - ResourceValue oldValue = list.get(value.getName()); - - if (oldValue != null) { - oldValue.replaceWith(value); - return; - } - } - - // empty list or no match found? add the given resource - list.put(value.getName(), value); - } - } - - @Override - public IResourceValue getValue(ResourceType type, String name) { - update(); - - // get the list for the given type - HashMap<String, ResourceValue> list = mResourceItems.get(type); - - if (list != null) { - return list.get(name); - } - - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java deleted file mode 100644 index 8b6c3c1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager; - -import com.android.ide.eclipse.common.AndroidConstants; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; - -/** - * ClassLoader able to load class from output of an Eclipse project. - */ -public final class ProjectClassLoader extends ClassLoader { - - private final IJavaProject mJavaProject; - private URLClassLoader mJarClassLoader; - private boolean mInsideJarClassLoader = false; - - public ProjectClassLoader(ClassLoader parentClassLoader, IProject project) { - super(parentClassLoader); - mJavaProject = JavaCore.create(project); - } - - @Override - protected Class<?> findClass(String name) throws ClassNotFoundException { - try { - // get the project output folder. - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IPath outputLocation = mJavaProject.getOutputLocation(); - IResource outRes = root.findMember(outputLocation); - if (outRes == null) { - throw new ClassNotFoundException(name); - } - - File outFolder = new File(outRes.getLocation().toOSString()); - - // get the class name segments - String[] segments = name.split("\\."); //$NON-NLS-1$ - - File classFile = getFile(outFolder, segments, 0); - if (classFile == null) { - if (mInsideJarClassLoader == false) { - // if no file matching the class name was found, look in the 3rd party jars - return loadClassFromJar(name); - } else { - throw new ClassNotFoundException(name); - } - } - - // load the content of the file and create the class. - FileInputStream fis = new FileInputStream(classFile); - byte[] data = new byte[(int)classFile.length()]; - int read = 0; - try { - read = fis.read(data); - } catch (IOException e) { - data = null; - } - fis.close(); - - if (data != null) { - Class<?> clazz = defineClass(null, data, 0, read); - if (clazz != null) { - return clazz; - } - } - } catch (Exception e) { - throw new ClassNotFoundException(e.getMessage()); - } - - throw new ClassNotFoundException(name); - } - - /** - * Returns the File matching the a certain path from a root {@link File}. - * <p/>The methods checks that the file ends in .class even though the last segment - * does not. - * @param parent the root of the file. - * @param segments the segments containing the path of the file - * @param index the offset at which to start looking into segments. - * @throws FileNotFoundException - */ - private File getFile(File parent, String[] segments, int index) - throws FileNotFoundException { - // reached the end with no match? - if (index == segments.length) { - throw new FileNotFoundException(); - } - - String toMatch = segments[index]; - File[] files = parent.listFiles(); - - // we're at the last segments. we look for a matching <file>.class - if (index == segments.length - 1) { - toMatch = toMatch + ".class"; - - if (files != null) { - for (File file : files) { - if (file.isFile() && file.getName().equals(toMatch)) { - return file; - } - } - } - - // no match? abort. - throw new FileNotFoundException(); - } - - String innerClassName = null; - - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - if (toMatch.equals(file.getName())) { - return getFile(file, segments, index+1); - } - } else if (file.getName().startsWith(toMatch)) { - if (innerClassName == null) { - StringBuilder sb = new StringBuilder(segments[index]); - for (int i = index + 1 ; i < segments.length ; i++) { - sb.append('$'); - sb.append(segments[i]); - } - sb.append(".class"); - - innerClassName = sb.toString(); - } - - if (file.getName().equals(innerClassName)) { - return file; - } - } - } - } - - return null; - } - - /** - * Loads a class from the 3rd party jar present in the project - * @throws ClassNotFoundException - */ - private Class<?> loadClassFromJar(String name) throws ClassNotFoundException { - if (mJarClassLoader == null) { - // get the OS path to all the external jars - URL[] jars = getExternalJars(); - - mJarClassLoader = new URLClassLoader(jars, this /* parent */); - } - - try { - // because a class loader always look in its parent loader first, we need to know - // that we are querying the jar classloader. This will let us know to not query - // it again for classes we don't find, or this would create an infinite loop. - mInsideJarClassLoader = true; - return mJarClassLoader.loadClass(name); - } finally { - mInsideJarClassLoader = false; - } - } - - /** - * Returns an array of external jar files used by the project. - * @return an array of OS-specific absolute file paths - */ - private final URL[] getExternalJars() { - // get a java project from it - IJavaProject javaProject = JavaCore.create(mJavaProject.getProject()); - - IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); - - ArrayList<URL> oslibraryList = new ArrayList<URL>(); - IClasspathEntry[] classpaths = javaProject.readRawClasspath(); - if (classpaths != null) { - for (IClasspathEntry e : classpaths) { - if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY || - e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - // if this is a classpath variable reference, we resolve it. - if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - e = JavaCore.getResolvedClasspathEntry(e); - } - - // get the IPath - IPath path = e.getPath(); - - // check the name ends with .jar - if (AndroidConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) { - boolean local = false; - IResource resource = wsRoot.findMember(path); - if (resource != null && resource.exists() && - resource.getType() == IResource.FILE) { - local = true; - try { - oslibraryList.add( - new File(resource.getLocation().toOSString()).toURL()); - } catch (MalformedURLException mue) { - // pass - } - } - - if (local == false) { - // if the jar path doesn't match a workspace resource, - // then we get an OSString and check if this links to a valid file. - String osFullPath = path.toOSString(); - - File f = new File(osFullPath); - if (f.exists()) { - try { - oslibraryList.add(f.toURL()); - } catch (MalformedURLException mue) { - // pass - } - } - } - } - } - } - } - - return oslibraryList.toArray(new URL[oslibraryList.size()]); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResourceItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResourceItem.java deleted file mode 100644 index ba770b2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResourceItem.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.android.ide.eclipse.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * Base class for Resource Item coming from an Android Project. - */ -public abstract class ProjectResourceItem extends ResourceItem { - - private final static Comparator<ResourceFile> sComparator = new Comparator<ResourceFile>() { - public int compare(ResourceFile file1, ResourceFile file2) { - // get both FolderConfiguration and compare them - FolderConfiguration fc1 = file1.getFolder().getConfiguration(); - FolderConfiguration fc2 = file2.getFolder().getConfiguration(); - - return fc1.compareTo(fc2); - } - }; - - /** - * List of files generating this ResourceItem. - */ - protected final ArrayList<ResourceFile> mFiles = new ArrayList<ResourceFile>(); - - /** - * Constructs a new ResourceItem. - * @param name the name of the resource as it appears in the XML and R.java files. - */ - public ProjectResourceItem(String name) { - super(name); - } - - /** - * Returns whether the resource item is editable directly. - * <p/> - * This is typically the case for resources that don't have alternate versions, or resources - * of type {@link ResourceType#ID} that aren't declared inline. - */ - public abstract boolean isEditableDirectly(); - - /** - * Adds a new version of this resource item, by adding its {@link ResourceFile}. - * @param file the {@link ResourceFile} object. - */ - protected void add(ResourceFile file) { - mFiles.add(file); - } - - /** - * Reset the item by emptying its version list. - */ - protected void reset() { - mFiles.clear(); - } - - /** - * Returns the sorted list of {@link ResourceItem} objects for this resource item. - */ - public ResourceFile[] getSourceFileArray() { - ArrayList<ResourceFile> list = new ArrayList<ResourceFile>(); - list.addAll(mFiles); - - Collections.sort(list, sComparator); - - return list.toArray(new ResourceFile[list.size()]); - } - - /** - * Returns the list of {@link ResourceItem} objects for this resource item. - */ - public List<ResourceFile> getSourceFileList() { - return Collections.unmodifiableList(mFiles); - } - - - /** - * Replaces the content of the receiver with the ResourceItem received as parameter. - * @param item - */ - protected void replaceWith(ProjectResourceItem item) { - mFiles.clear(); - mFiles.addAll(item.mFiles); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java deleted file mode 100644 index 40e4e3b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java +++ /dev/null @@ -1,804 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.configurations.LanguageQualifier; -import com.android.ide.eclipse.editors.resources.configurations.RegionQualifier; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFolder; -import com.android.layoutlib.api.IResourceValue; -import com.android.layoutlib.utils.ResourceValue; - -import org.eclipse.core.resources.IFolder; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Represents the resources of a project. This is a file view of the resources, with handling - * for the alternate resource types. For a compiled view use CompiledResources. - */ -public class ProjectResources implements IResourceRepository { - private final HashMap<ResourceFolderType, List<ResourceFolder>> mFolderMap = - new HashMap<ResourceFolderType, List<ResourceFolder>>(); - - private final HashMap<ResourceType, List<ProjectResourceItem>> mResourceMap = - new HashMap<ResourceType, List<ProjectResourceItem>>(); - - /** Map of (name, id) for resources of type {@link ResourceType#ID} coming from R.java */ - private Map<String, Map<String, Integer>> mResourceValueMap; - /** Map of (id, [name, resType]) for all resources coming from R.java */ - private Map<Integer, String[]> mResIdValueToNameMap; - /** Map of (int[], name) for styleable resources coming from R.java */ - private Map<IntArrayWrapper, String> mStyleableValueToNameMap; - - /** Cached list of {@link IdResourceItem}. This is mix of IdResourceItem created by - * {@link MultiResourceFile} for ids coming from XML files under res/values and - * {@link IdResourceItem} created manually, from the list coming from R.java */ - private final ArrayList<IdResourceItem> mIdResourceList = new ArrayList<IdResourceItem>(); - - private final boolean mIsFrameworkRepository; - - private final IntArrayWrapper mWrapper = new IntArrayWrapper(null); - - public ProjectResources(boolean isFrameworkRepository) { - mIsFrameworkRepository = isFrameworkRepository; - } - - public boolean isSystemRepository() { - return mIsFrameworkRepository; - } - - /** - * Adds a Folder Configuration to the project. - * @param type The resource type. - * @param config The resource configuration. - * @param folder The workspace folder object. - * @return the {@link ResourceFolder} object associated to this folder. - */ - protected ResourceFolder add(ResourceFolderType type, FolderConfiguration config, - IAbstractFolder folder) { - // get the list for the resource type - List<ResourceFolder> list = mFolderMap.get(type); - - if (list == null) { - list = new ArrayList<ResourceFolder>(); - - ResourceFolder cf = new ResourceFolder(type, config, folder, mIsFrameworkRepository); - list.add(cf); - - mFolderMap.put(type, list); - - return cf; - } - - // look for an already existing folder configuration. - for (ResourceFolder cFolder : list) { - if (cFolder.mConfiguration.equals(config)) { - // config already exist. Nothing to be done really, besides making sure - // the IFolder object is up to date. - cFolder.mFolder = folder; - return cFolder; - } - } - - // If we arrive here, this means we didn't find a matching configuration. - // So we add one. - ResourceFolder cf = new ResourceFolder(type, config, folder, mIsFrameworkRepository); - list.add(cf); - - return cf; - } - - /** - * Removes a {@link ResourceFolder} associated with the specified {@link IAbstractFolder}. - * @param type The type of the folder - * @param folder the IFolder object. - */ - protected void removeFolder(ResourceFolderType type, IFolder folder) { - // get the list of folders for the resource type. - List<ResourceFolder> list = mFolderMap.get(type); - - if (list != null) { - int count = list.size(); - for (int i = 0 ; i < count ; i++) { - ResourceFolder resFolder = list.get(i); - if (resFolder.getFolder().getIFolder().equals(folder)) { - // we found the matching ResourceFolder. we need to remove it. - list.remove(i); - - // we now need to invalidate this resource type. - // The easiest way is to touch one of the other folders of the same type. - if (list.size() > 0) { - list.get(0).touch(); - } else { - // if the list is now empty, and we have a single ResouceType out of this - // ResourceFolderType, then we are done. - // However, if another ResourceFolderType can generate similar ResourceType - // than this, we need to update those ResourceTypes as well. - // For instance, if the last "drawable-*" folder is deleted, we need to - // refresh the ResourceItem associated with ResourceType.DRAWABLE. - // Those can be found in ResourceFolderType.DRAWABLE but also in - // ResourceFolderType.VALUES. - // If we don't find a single folder to touch, then it's fine, as the top - // level items (the list of generated resource types) is not cached - // (for now) - - // get the lists of ResourceTypes generated by this ResourceFolderType - ResourceType[] resTypes = FolderTypeRelationship.getRelatedResourceTypes( - type); - - // for each of those, make sure to find one folder to touch so that the - // list of ResourceItem associated with the type is rebuilt. - for (ResourceType resType : resTypes) { - // get the list of folder that can generate this type - ResourceFolderType[] folderTypes = - FolderTypeRelationship.getRelatedFolders(resType); - - // we only need to touch one folder in any of those (since it's one - // folder per type, not per folder type). - for (ResourceFolderType folderType : folderTypes) { - List<ResourceFolder> resFolders = mFolderMap.get(folderType); - - if (resFolders != null && resFolders.size() > 0) { - resFolders.get(0).touch(); - break; - } - } - } - } - - // we're done updating/touching, we can stop - break; - } - } - } - } - - - /** - * Returns a list of {@link ResourceFolder} for a specific {@link ResourceFolderType}. - * @param type The {@link ResourceFolderType} - */ - public List<ResourceFolder> getFolders(ResourceFolderType type) { - return mFolderMap.get(type); - } - - /* (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.IResourceRepository#getAvailableResourceTypes() - */ - public ResourceType[] getAvailableResourceTypes() { - ArrayList<ResourceType> list = new ArrayList<ResourceType>(); - - // For each key, we check if there's a single ResourceType match. - // If not, we look for the actual content to give us the resource type. - - for (ResourceFolderType folderType : mFolderMap.keySet()) { - ResourceType types[] = FolderTypeRelationship.getRelatedResourceTypes(folderType); - if (types.length == 1) { - // before we add it we check if it's not already present, since a ResourceType - // could be created from multiple folders, even for the folders that only create - // one type of resource (drawable for instance, can be created from drawable/ and - // values/) - if (list.indexOf(types[0]) == -1) { - list.add(types[0]); - } - } else { - // there isn't a single resource type out of this folder, so we look for all - // content. - List<ResourceFolder> folders = mFolderMap.get(folderType); - if (folders != null) { - for (ResourceFolder folder : folders) { - Collection<ResourceType> folderContent = folder.getResourceTypes(); - - // then we add them, but only if they aren't already in the list. - for (ResourceType folderResType : folderContent) { - if (list.indexOf(folderResType) == -1) { - list.add(folderResType); - } - } - } - } - } - } - - // in case ResourceType.ID haven't been added yet because there's no id defined - // in XML, we check on the list of compiled id resources. - if (list.indexOf(ResourceType.ID) == -1 && mResourceValueMap != null) { - Map<String, Integer> map = mResourceValueMap.get(ResourceType.ID.getName()); - if (map != null && map.size() > 0) { - list.add(ResourceType.ID); - } - } - - // at this point the list is full of ResourceType defined in the files. - // We need to sort it. - Collections.sort(list); - - return list.toArray(new ResourceType[list.size()]); - } - - /* (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.IResourceRepository#getResources(com.android.ide.eclipse.common.resources.ResourceType) - */ - public ProjectResourceItem[] getResources(ResourceType type) { - checkAndUpdate(type); - - if (type == ResourceType.ID) { - synchronized (mIdResourceList) { - return mIdResourceList.toArray(new ProjectResourceItem[mIdResourceList.size()]); - } - } - - List<ProjectResourceItem> items = mResourceMap.get(type); - - return items.toArray(new ProjectResourceItem[items.size()]); - } - - /* (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.IResourceRepository#hasResources(com.android.ide.eclipse.common.resources.ResourceType) - */ - public boolean hasResources(ResourceType type) { - checkAndUpdate(type); - - if (type == ResourceType.ID) { - synchronized (mIdResourceList) { - return mIdResourceList.size() > 0; - } - } - - List<ProjectResourceItem> items = mResourceMap.get(type); - return (items != null && items.size() > 0); - } - - /** - * Returns the {@link ResourceFolder} associated with a {@link IFolder}. - * @param folder The {@link IFolder} object. - * @return the {@link ResourceFolder} or null if it was not found. - */ - public ResourceFolder getResourceFolder(IFolder folder) { - for (List<ResourceFolder> list : mFolderMap.values()) { - for (ResourceFolder resFolder : list) { - if (resFolder.getFolder().getIFolder().equals(folder)) { - return resFolder; - } - } - } - - return null; - } - - /** - * Returns the {@link ResourceFile} matching the given name, {@link ResourceFolderType} and - * configuration. - * <p/>This only works with files generating one resource named after the file (for instance, - * layouts, bitmap based drawable, xml, anims). - * @return the matching file or <code>null</code> if no match was found. - */ - public ResourceFile getMatchingFile(String name, ResourceFolderType type, - FolderConfiguration config) { - // get the folders for the given type - List<ResourceFolder> folders = mFolderMap.get(type); - - // look for folders containing a file with the given name. - ArrayList<ResourceFolder> matchingFolders = new ArrayList<ResourceFolder>(); - - // remove the folders that do not have a file with the given name, or if their config - // is incompatible. - for (int i = 0 ; i < folders.size(); i++) { - ResourceFolder folder = folders.get(i); - - if (folder.hasFile(name) == true) { - matchingFolders.add(folder); - } - } - - // from those, get the folder with a config matching the given reference configuration. - Resource match = findMatchingConfiguredResource(matchingFolders, config); - - // do we have a matching folder? - if (match instanceof ResourceFolder) { - // get the ResourceFile from the filename - return ((ResourceFolder)match).getFile(name); - } - - return null; - } - - /** - * Returns the resources values matching a given {@link FolderConfiguration}. - * @param referenceConfig the configuration that each value must match. - */ - public Map<String, Map<String, IResourceValue>> getConfiguredResources( - FolderConfiguration referenceConfig) { - - Map<String, Map<String, IResourceValue>> map = - new HashMap<String, Map<String, IResourceValue>>(); - - // special case for Id since there's a mix of compiled id (declared inline) and id declared - // in the XML files. - if (mIdResourceList.size() > 0) { - Map<String, IResourceValue> idMap = new HashMap<String, IResourceValue>(); - String idType = ResourceType.ID.getName(); - for (IdResourceItem id : mIdResourceList) { - // FIXME: cache the ResourceValue! - idMap.put(id.getName(), new ResourceValue(idType, id.getName(), - mIsFrameworkRepository)); - } - - map.put(ResourceType.ID.getName(), idMap); - } - - Set<ResourceType> keys = mResourceMap.keySet(); - for (ResourceType key : keys) { - // we don't process ID resources since we already did it above. - if (key != ResourceType.ID) { - map.put(key.getName(), getConfiguredResource(key, referenceConfig)); - } - } - - return map; - } - - /** - * Loads all the resources. Essentially this forces to load the values from the - * {@link ResourceFile} objects to make sure they are up to date and loaded - * in {@link #mResourceMap}. - */ - public void loadAll() { - // gets all the resource types available. - ResourceType[] types = getAvailableResourceTypes(); - - // loop on them and load them - for (ResourceType type: types) { - checkAndUpdate(type); - } - } - - /** - * Resolves a compiled resource id into the resource name and type - * @param id - * @return an array of 2 strings { name, type } or null if the id could not be resolved - */ - public String[] resolveResourceValue(int id) { - if (mResIdValueToNameMap != null) { - return mResIdValueToNameMap.get(id); - } - - return null; - } - - /** - * Resolves a compiled resource id of type int[] into the resource name. - */ - public String resolveResourceValue(int[] id) { - if (mStyleableValueToNameMap != null) { - mWrapper.set(id); - return mStyleableValueToNameMap.get(mWrapper); - } - - return null; - } - - /** - * Returns the value of a resource by its type and name. - */ - public Integer getResourceValue(String type, String name) { - if (mResourceValueMap != null) { - Map<String, Integer> map = mResourceValueMap.get(type); - if (map != null) { - return map.get(name); - } - } - - return null; - } - - /** - * Returns the list of languages used in the resources. - */ - public Set<String> getLanguages() { - Set<String> set = new HashSet<String>(); - - Collection<List<ResourceFolder>> folderList = mFolderMap.values(); - for (List<ResourceFolder> folderSubList : folderList) { - for (ResourceFolder folder : folderSubList) { - FolderConfiguration config = folder.getConfiguration(); - LanguageQualifier lang = config.getLanguageQualifier(); - if (lang != null) { - set.add(lang.getStringValue()); - } - } - } - - return set; - } - - /** - * Returns the list of regions used in the resources with the given language. - * @param currentLanguage the current language the region must be associated with. - */ - public Set<String> getRegions(String currentLanguage) { - Set<String> set = new HashSet<String>(); - - Collection<List<ResourceFolder>> folderList = mFolderMap.values(); - for (List<ResourceFolder> folderSubList : folderList) { - for (ResourceFolder folder : folderSubList) { - FolderConfiguration config = folder.getConfiguration(); - - // get the language - LanguageQualifier lang = config.getLanguageQualifier(); - if (lang != null && lang.getStringValue().equals(currentLanguage)) { - RegionQualifier region = config.getRegionQualifier(); - if (region != null) { - set.add(region.getStringValue()); - } - } - } - } - - return set; - } - - /** - * Returns a map of (resource name, resource value) for the given {@link ResourceType}. - * <p/>The values returned are taken from the resource files best matching a given - * {@link FolderConfiguration}. - * @param type the type of the resources. - * @param referenceConfig the configuration to best match. - */ - private Map<String, IResourceValue> getConfiguredResource(ResourceType type, - FolderConfiguration referenceConfig) { - // get the resource item for the given type - List<ProjectResourceItem> items = mResourceMap.get(type); - - // create the map - HashMap<String, IResourceValue> map = new HashMap<String, IResourceValue>(); - - for (ProjectResourceItem item : items) { - // get the source files generating this resource - List<ResourceFile> list = item.getSourceFileList(); - - // look for the best match for the given configuration - Resource match = findMatchingConfiguredResource(list, referenceConfig); - - if (match instanceof ResourceFile) { - ResourceFile matchResFile = (ResourceFile)match; - - // get the value of this configured resource. - IResourceValue value = matchResFile.getValue(type, item.getName()); - - if (value != null) { - map.put(item.getName(), value); - } - } - } - - return map; - } - - /** - * Returns the best matching {@link Resource}. - * @param resources the list of {@link Resource} to choose from. - * @param referenceConfig the {@link FolderConfiguration} to match. - */ - private Resource findMatchingConfiguredResource(List<? extends Resource> resources, - FolderConfiguration referenceConfig) { - // look for resources with the maximum number of qualifier match. - int currentMax = -1; - ArrayList<Resource> matchingResources = new ArrayList<Resource>(); - for (int i = 0 ; i < resources.size(); i++) { - Resource res = resources.get(i); - - int count = res.getConfiguration().match(referenceConfig); - if (count > currentMax) { - matchingResources.clear(); - matchingResources.add(res); - currentMax = count; - } else if (count != -1 && count == currentMax) { - matchingResources.add(res); - } - } - - // if we have more than one match, we look for the match with the qualifiers with the - // highest priority. - Resource resMatch = null; - if (matchingResources.size() == 1) { - resMatch = matchingResources.get(0); - } else if (matchingResources.size() > 1) { - // More than one resource with the same number of qualifier match. - // We loop, looking for the resource with the highest priority qualifiers. - ArrayList<Resource> tmpResources = new ArrayList<Resource>(); - int startIndex = 0; - while (matchingResources.size() > 1) { - int highest = -1; - for (int i = 0 ; i < matchingResources.size() ; i++) { - Resource folder = matchingResources.get(i); - - // get highest priority qualifiers. - int m = folder.getConfiguration().getHighestPriorityQualifier(startIndex); - - // add to the list if highest. - if (m != -1) { - if (highest == -1 || m == highest) { - tmpResources.add(folder); - highest = m; - } else if (m < highest) { // highest priority == lowest index. - tmpResources.clear(); - tmpResources.add(folder); - } - } - } - - // at this point, we have a list with 1+ resources that all have the same highest - // priority qualifiers. Go through the list again looking for the next highest - // priority qualifier. - startIndex = highest + 1; - - // this should not happen, but it's better to check. - if (matchingResources.size() == tmpResources.size() && highest == -1) { - // this means all the resources match with the same qualifiers - // (highest == -1 means we reached the end of the qualifier list) - // In this case, we arbitrarily take the first resource. - matchingResources.clear(); - matchingResources.add(tmpResources.get(0)); - } else { - matchingResources.clear(); - matchingResources.addAll(tmpResources); - } - tmpResources.clear(); - } - - // we should have only one match here. - resMatch = matchingResources.get(0); - } - - return resMatch; - } - - /** - * Checks if the list of {@link ResourceItem}s for the specified {@link ResourceType} needs - * to be updated. - * @param type the Resource Type. - */ - private void checkAndUpdate(ResourceType type) { - // get the list of folder that can output this type - ResourceFolderType[] folderTypes = FolderTypeRelationship.getRelatedFolders(type); - - for (ResourceFolderType folderType : folderTypes) { - List<ResourceFolder> folders = mFolderMap.get(folderType); - - if (folders != null) { - for (ResourceFolder folder : folders) { - if (folder.isTouched()) { - // if this folder is touched we need to update all the types that can - // be generated from a file in this folder. - // This will include 'type' obviously. - ResourceType[] resTypes = FolderTypeRelationship.getRelatedResourceTypes( - folderType); - for (ResourceType resType : resTypes) { - update(resType); - } - return; - } - } - } - } - } - - /** - * Updates the list of {@link ResourceItem} objects associated with a {@link ResourceType}. - * This will reset the touch status of all the folders that can generate this resource type. - * @param type the Resource Type. - */ - private void update(ResourceType type) { - // get the cache list, and lets make a backup - List<ProjectResourceItem> items = mResourceMap.get(type); - List<ProjectResourceItem> backup = new ArrayList<ProjectResourceItem>(); - - if (items == null) { - items = new ArrayList<ProjectResourceItem>(); - mResourceMap.put(type, items); - } else { - // backup the list - backup.addAll(items); - - // we reset the list itself. - items.clear(); - } - - // get the list of folder that can output this type - ResourceFolderType[] folderTypes = FolderTypeRelationship.getRelatedFolders(type); - - for (ResourceFolderType folderType : folderTypes) { - List<ResourceFolder> folders = mFolderMap.get(folderType); - - if (folders != null) { - for (ResourceFolder folder : folders) { - items.addAll(folder.getResources(type, this)); - folder.resetTouch(); - } - } - } - - // now items contains the new list. We "merge" it with the backup list. - // Basically, we need to keep the old instances of ResourceItem (where applicable), - // but replace them by the content of the new items. - // This will let the resource explorer keep the expanded state of the nodes whose data - // is a ResourceItem object. - if (backup.size() > 0) { - // this is not going to change as we're only replacing instances. - int count = items.size(); - - for (int i = 0 ; i < count;) { - // get the "new" item - ProjectResourceItem item = items.get(i); - - // look for a similar item in the old list. - ProjectResourceItem foundOldItem = null; - for (ProjectResourceItem oldItem : backup) { - if (oldItem.getName().equals(item.getName())) { - foundOldItem = oldItem; - break; - } - } - - if (foundOldItem != null) { - // erase the data of the old item with the data from the new one. - foundOldItem.replaceWith(item); - - // remove the old and new item from their respective lists - items.remove(i); - backup.remove(foundOldItem); - - // add the old item to the new list - items.add(foundOldItem); - } else { - // this is a new item, we skip to the next object - i++; - } - } - } - - // if this is the ResourceType.ID, we create the actual list, from this list and - // the compiled resource list. - if (type == ResourceType.ID) { - mergeIdResources(); - } else { - // else this is the list that will actually be displayed, so we sort it. - Collections.sort(items); - } - } - - /** - * Looks up an existing {@link ProjectResourceItem} by {@link ResourceType} and name. - * @param type the Resource Type. - * @param name the Resource name. - * @return the existing ResourceItem or null if no match was found. - */ - protected ProjectResourceItem findResourceItem(ResourceType type, String name) { - List<ProjectResourceItem> list = mResourceMap.get(type); - - for (ProjectResourceItem item : list) { - if (name.equals(item.getName())) { - return item; - } - } - - return null; - } - - /** - * Sets compiled resource information. - * @param resIdValueToNameMap a map of compiled resource id to resource name. - * The map is acquired by the {@link ProjectResources} object. - * @param styleableValueMap - * @param resourceValueMap a map of (name, id) for resources of type {@link ResourceType#ID}. - * The list is acquired by the {@link ProjectResources} object. - */ - void setCompiledResources(Map<Integer, String[]> resIdValueToNameMap, - Map<IntArrayWrapper, String> styleableValueMap, - Map<String, Map<String, Integer>> resourceValueMap) { - mResourceValueMap = resourceValueMap; - mResIdValueToNameMap = resIdValueToNameMap; - mStyleableValueToNameMap = styleableValueMap; - mergeIdResources(); - } - - /** - * Merges the list of ID resource coming from R.java and the list of ID resources - * coming from XML declaration into the cached list {@link #mIdResourceList}. - */ - void mergeIdResources() { - // get the list of IDs coming from XML declaration. Those ids are present in - // mCompiledIdResources already, so we'll need to use those instead of creating - // new IdResourceItem - List<ProjectResourceItem> xmlIdResources = mResourceMap.get(ResourceType.ID); - - synchronized (mIdResourceList) { - // copy the currently cached items. - ArrayList<IdResourceItem> oldItems = new ArrayList<IdResourceItem>(); - oldItems.addAll(mIdResourceList); - - // empty the current list - mIdResourceList.clear(); - - // get the list of compile id resources. - Map<String, Integer> idMap = null; - if (mResourceValueMap != null) { - idMap = mResourceValueMap.get(ResourceType.ID.getName()); - } - - if (idMap == null) { - if (xmlIdResources != null) { - for (ProjectResourceItem resourceItem : xmlIdResources) { - // check the actual class just for safety. - if (resourceItem instanceof IdResourceItem) { - mIdResourceList.add((IdResourceItem)resourceItem); - } - } - } - } else { - // loop on the full list of id, and look for a match in the old list, - // in the list coming from XML (in case a new XML item was created.) - - Set<String> idSet = idMap.keySet(); - - idLoop: for (String idResource : idSet) { - // first look in the XML list in case an id went from inline to XML declared. - if (xmlIdResources != null) { - for (ProjectResourceItem resourceItem : xmlIdResources) { - if (resourceItem instanceof IdResourceItem && - resourceItem.getName().equals(idResource)) { - mIdResourceList.add((IdResourceItem)resourceItem); - continue idLoop; - } - } - } - - // if we haven't found it, look in the old items. - int count = oldItems.size(); - for (int i = 0 ; i < count ; i++) { - IdResourceItem resourceItem = oldItems.get(i); - if (resourceItem.getName().equals(idResource)) { - oldItems.remove(i); - mIdResourceList.add(resourceItem); - continue idLoop; - } - } - - // if we haven't found it, it looks like it's a new id that was - // declared inline. - mIdResourceList.add(new IdResourceItem(idResource, - true /* isDeclaredInline */)); - } - } - - // now we sort the list - Collections.sort(mIdResourceList); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/Resource.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/Resource.java deleted file mode 100644 index dd8d080..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/Resource.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; - -/** - * Base class for file system resource items (Folders, Files). - */ -public abstract class Resource { - private boolean mTouched = true; - - /** - * Returns the {@link FolderConfiguration} for this object. - */ - public abstract FolderConfiguration getConfiguration(); - - /** - * Indicates that the underlying file was changed. - */ - public final void touch() { - mTouched = true; - } - - public final boolean isTouched() { - return mTouched; - } - - public final void resetTouch() { - mTouched = false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFile.java deleted file mode 100644 index f927a9a..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFile.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFile; -import com.android.layoutlib.api.IResourceValue; - -import java.util.Collection; - -/** - * Represents a Resource file (a file under $Project/res/) - */ -public abstract class ResourceFile extends Resource { - - private final IAbstractFile mFile; - private final ResourceFolder mFolder; - - protected ResourceFile(IAbstractFile file, ResourceFolder folder) { - mFile = file; - mFolder = folder; - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.manager.Resource#getConfiguration() - */ - @Override - public FolderConfiguration getConfiguration() { - return mFolder.getConfiguration(); - } - - /** - * Returns the IFile associated with the ResourceFile. - */ - public final IAbstractFile getFile() { - return mFile; - } - - /** - * Returns the parent folder as a {@link ResourceFolder}. - */ - public final ResourceFolder getFolder() { - return mFolder; - } - - /** - * Returns whether the resource is a framework resource. - */ - public final boolean isFramework() { - return mFolder.isFramework(); - } - - /** - * Returns the list of {@link ResourceType} generated by the file. - */ - public abstract ResourceType[] getResourceTypes(); - - /** - * Returns whether the file generated a resource of a specific type. - * @param type The {@link ResourceType} - */ - public abstract boolean hasResources(ResourceType type); - - /** - * Get the list of {@link ProjectResourceItem} of a specific type generated by the file. - * This method must make sure not to create duplicate. - * @param type The type of {@link ProjectResourceItem} to return. - * @param projectResources The global Project Resource object, allowing the implementation to - * query for already existing {@link ProjectResourceItem} - * @return The list of <b>new</b> {@link ProjectResourceItem} - * @see ProjectResources#findResourceItem(ResourceType, String) - */ - public abstract Collection<ProjectResourceItem> getResources(ResourceType type, - ProjectResources projectResources); - - /** - * Returns the value of a resource generated by this file by {@link ResourceType} and name. - * <p/>If no resource match, <code>null</code> is returned. - * @param type the type of the resource. - * @param name the name of the resource. - */ - public abstract IResourceValue getValue(ResourceType type, String name); -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java deleted file mode 100644 index 98f5b39..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFile; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFolder; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * Resource Folder class. Contains list of {@link ResourceFile}s, - * the {@link FolderConfiguration}, and a link to the workspace {@link IFolder} object. - */ -public final class ResourceFolder extends Resource { - ResourceFolderType mType; - FolderConfiguration mConfiguration; - IAbstractFolder mFolder; - ArrayList<ResourceFile> mFiles = null; - private final boolean mIsFramework; - - /** - * Creates a new {@link ResourceFolder} - * @param type The type of the folder - * @param config The configuration of the folder - * @param folder The associated {@link IAbstractFolder} object. - * @param isFrameworkRepository - */ - public ResourceFolder(ResourceFolderType type, FolderConfiguration config, - IAbstractFolder folder, boolean isFrameworkRepository) { - mType = type; - mConfiguration = config; - mFolder = folder; - mIsFramework = isFrameworkRepository; - } - - /** - * Adds a {@link ResourceFile} to the folder. - * @param file The {@link ResourceFile}. - */ - public void addFile(ResourceFile file) { - if (mFiles == null) { - mFiles = new ArrayList<ResourceFile>(); - } - - mFiles.add(file); - } - - /** - * Attempts to remove the {@link ResourceFile} associated with a specified {@link IFile}. - * @param file the IFile object. - */ - public void removeFile(IFile file) { - if (mFiles != null) { - int count = mFiles.size(); - for (int i = 0 ; i < count ; i++) { - ResourceFile resFile = mFiles.get(i); - if (resFile != null) { - IFile iFile = resFile.getFile().getIFile(); - if (iFile != null && iFile.equals(file)) { - mFiles.remove(i); - touch(); - } - } - } - } - } - - /** - * Returns the {@link IFolder} associated with this object. - */ - public IAbstractFolder getFolder() { - return mFolder; - } - - /** - * Returns the {@link ResourceFolderType} of this object. - */ - public ResourceFolderType getType() { - return mType; - } - - /** - * Returns whether the folder is a framework resource folder. - */ - public boolean isFramework() { - return mIsFramework; - } - - /** - * Returns the list of {@link ResourceType}s generated by the files inside this folder. - */ - public Collection<ResourceType> getResourceTypes() { - ArrayList<ResourceType> list = new ArrayList<ResourceType>(); - - if (mFiles != null) { - for (ResourceFile file : mFiles) { - ResourceType[] types = file.getResourceTypes(); - - // loop through those and add them to the main list, - // if they are not already present - if (types != null) { - for (ResourceType resType : types) { - if (list.indexOf(resType) == -1) { - list.add(resType); - } - } - } - } - } - - return list; - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.manager.Resource#getConfiguration() - */ - @Override - public FolderConfiguration getConfiguration() { - return mConfiguration; - } - - /** - * Returns whether the folder contains a file with the given name. - * @param name the name of the file. - */ - public boolean hasFile(String name) { - return mFolder.hasFile(name); - } - - /** - * Returns the {@link ResourceFile} matching a {@link IAbstractFile} object. - * @param file The {@link IFile} object. - * @return the {@link ResourceFile} or null if no match was found. - */ - public ResourceFile getFile(IAbstractFile file) { - if (mFiles != null) { - for (ResourceFile f : mFiles) { - if (f.getFile().equals(file)) { - return f; - } - } - } - return null; - } - - /** - * Returns the {@link ResourceFile} matching a {@link IFile} object. - * @param file The {@link IFile} object. - * @return the {@link ResourceFile} or null if no match was found. - */ - public ResourceFile getFile(IFile file) { - if (mFiles != null) { - for (ResourceFile f : mFiles) { - IFile iFile = f.getFile().getIFile(); - if (iFile != null && iFile.equals(file)) { - return f; - } - } - } - return null; - } - - - /** - * Returns the {@link ResourceFile} matching a given name. - * @param filename The name of the file to return. - * @return the {@link ResourceFile} or <code>null</code> if no match was found. - */ - public ResourceFile getFile(String filename) { - if (mFiles != null) { - for (ResourceFile f : mFiles) { - if (f.getFile().getName().equals(filename)) { - return f; - } - } - } - return null; - } - - /** - * Returns whether a file in the folder is generating a resource of a specified type. - * @param type The {@link ResourceType} being looked up. - */ - public boolean hasResources(ResourceType type) { - // Check if the folder type is able to generate resource of the type that was asked. - // this is a first check to avoid going through the files. - ResourceFolderType[] folderTypes = FolderTypeRelationship.getRelatedFolders(type); - - boolean valid = false; - for (ResourceFolderType rft : folderTypes) { - if (rft == mType) { - valid = true; - break; - } - } - - if (valid) { - if (mFiles != null) { - for (ResourceFile f : mFiles) { - if (f.hasResources(type)) { - return true; - } - } - } - } - return false; - } - - /** - * Get the list of {@link ResourceItem} of a specific type generated by all the files - * in the folder. - * This method must make sure not to create duplicates. - * @param type The type of {@link ResourceItem} to return. - * @param projectResources The global Project Resource object, allowing the implementation to - * query for already existing {@link ResourceItem} - * @return The list of <b>new</b> {@link ResourceItem} - * @see ProjectResources#findResourceItem(ResourceType, String) - */ - public Collection<ProjectResourceItem> getResources(ResourceType type, - ProjectResources projectResources) { - Collection<ProjectResourceItem> list = new ArrayList<ProjectResourceItem>(); - if (mFiles != null) { - for (ResourceFile f : mFiles) { - list.addAll(f.getResources(type, projectResources)); - } - } - return list; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java deleted file mode 100644 index 5fc7393..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.sdklib.SdkConstants; - -/** - * Enum representing a type of resource folder. - */ -public enum ResourceFolderType { - ANIM(SdkConstants.FD_ANIM), - COLOR(SdkConstants.FD_COLOR), - DRAWABLE(SdkConstants.FD_DRAWABLE), - LAYOUT(SdkConstants.FD_LAYOUT), - MENU(SdkConstants.FD_MENU), - RAW(SdkConstants.FD_RAW), - VALUES(SdkConstants.FD_VALUES), - XML(SdkConstants.FD_XML); - - private final String mName; - - ResourceFolderType(String name) { - mName = name; - } - - public String getName() { - return mName; - } - - /** - * Returns the enum by name. - * @param name The enum string value. - * @return the enum or null if not found. - */ - public static ResourceFolderType getTypeByName(String name) { - for (ResourceFolderType rType : values()) { - if (rType.mName.equals(name)) { - return rType; - } - } - return null; - } - - /** - * Returns the {@link ResourceFolderType} from the folder name - * @param folderName The name of the folder. This must be a valid folder name in the format - * <code>resType[-resqualifiers[-resqualifiers[...]]</code> - * @return the <code>ResourceFolderType</code> representing the type of the folder, or - * <code>null</code> if no matching type was found. - */ - public static ResourceFolderType getFolderType(String folderName) { - // split the name of the folder in segments. - String[] folderSegments = folderName.split(FolderConfiguration.QUALIFIER_SEP); - - // get the enum for the resource type. - return getTypeByName(folderSegments[0]); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java deleted file mode 100644 index 6099008..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFolderListener; -import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener; -import com.android.ide.eclipse.editors.resources.manager.files.FileWrapper; -import com.android.ide.eclipse.editors.resources.manager.files.FolderWrapper; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFile; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFolder; -import com.android.ide.eclipse.editors.resources.manager.files.IFileWrapper; -import com.android.ide.eclipse.editors.resources.manager.files.IFolderWrapper; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; - -public final class ResourceManager implements IProjectListener, IFolderListener, IFileListener { - - private final static ResourceManager sThis = new ResourceManager(); - - /** List of the qualifier object helping for the parsing of folder names */ - private final ResourceQualifier[] mQualifiers; - - /** - * Map associating project resource with project objects. - */ - private final HashMap<IProject, ProjectResources> mMap = - new HashMap<IProject, ProjectResources>(); - - /** - * Sets up the resource manager with the global resource monitor. - * @param monitor The global resource monitor - */ - public static void setup(ResourceMonitor monitor) { - monitor.addProjectListener(sThis); - int mask = IResourceDelta.ADDED | IResourceDelta.REMOVED | IResourceDelta.CHANGED; - monitor.addFolderListener(sThis, mask); - monitor.addFileListener(sThis, mask); - - CompiledResourcesMonitor.setupMonitor(monitor); - } - - /** - * Returns the singleton instance. - */ - public static ResourceManager getInstance() { - return sThis; - } - - /** - * Returns the resources of a project. - * @param project The project - * @return a ProjectResources object or null if none was found. - */ - public ProjectResources getProjectResources(IProject project) { - return mMap.get(project); - } - - /** - * Processes folder event. - */ - public void folderChanged(IFolder folder, int kind) { - ProjectResources resources; - - final IProject project = folder.getProject(); - - try { - if (project.hasNature(AndroidConstants.NATURE) == false) { - return; - } - } catch (CoreException e) { - // can't get the project nature? return! - return; - } - - switch (kind) { - case IResourceDelta.ADDED: - // checks if the folder is under res. - IPath path = folder.getFullPath(); - - // the path will be project/res/<something> - if (path.segmentCount() == 3) { - if (isInResFolder(path)) { - // get the project and its resource object. - resources = mMap.get(project); - - // if it doesn't exist, we create it. - if (resources == null) { - resources = new ProjectResources(false /* isFrameworkRepository */); - mMap.put(project, resources); - } - - processFolder(new IFolderWrapper(folder), resources); - } - } - break; - case IResourceDelta.CHANGED: - resources = mMap.get(folder.getProject()); - if (resources != null) { - ResourceFolder resFolder = resources.getResourceFolder(folder); - if (resFolder != null) { - resFolder.touch(); - } - } - break; - case IResourceDelta.REMOVED: - resources = mMap.get(folder.getProject()); - if (resources != null) { - // lets get the folder type - ResourceFolderType type = ResourceFolderType.getFolderType(folder.getName()); - - resources.removeFolder(type, folder); - } - break; - } - } - - /* (non-Javadoc) - * Sent when a file changed. Depending on the file being changed, and the type of change (ADDED, - * REMOVED, CHANGED), the file change is processed to update the resource manager data. - * - * @param file The file that changed. - * @param markerDeltas The marker deltas for the file. - * @param kind The change kind. This is equivalent to - * {@link IResourceDelta#accept(IResourceDeltaVisitor)} - * - * @see IFileListener#fileChanged - */ - public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) { - ProjectResources resources; - - final IProject project = file.getProject(); - - try { - if (project.hasNature(AndroidConstants.NATURE) == false) { - return; - } - } catch (CoreException e) { - // can't get the project nature? return! - return; - } - - switch (kind) { - case IResourceDelta.ADDED: - // checks if the file is under res/something. - IPath path = file.getFullPath(); - - if (path.segmentCount() == 4) { - if (isInResFolder(path)) { - // get the project and its resources - resources = mMap.get(project); - - IContainer container = file.getParent(); - if (container instanceof IFolder && resources != null) { - - ResourceFolder folder = resources.getResourceFolder((IFolder)container); - - if (folder != null) { - processFile(new IFileWrapper(file), folder); - } - } - } - } - break; - case IResourceDelta.CHANGED: - // try to find a matching ResourceFile - resources = mMap.get(project); - if (resources != null) { - IContainer container = file.getParent(); - if (container instanceof IFolder) { - ResourceFolder resFolder = resources.getResourceFolder((IFolder)container); - - // we get the delete on the folder before the file, so it is possible - // the associated ResourceFolder doesn't exist anymore. - if (resFolder != null) { - // get the resourceFile, and touch it. - ResourceFile resFile = resFolder.getFile(file); - if (resFile != null) { - resFile.touch(); - } - } - } - } - break; - case IResourceDelta.REMOVED: - // try to find a matching ResourceFile - resources = mMap.get(project); - if (resources != null) { - IContainer container = file.getParent(); - if (container instanceof IFolder) { - ResourceFolder resFolder = resources.getResourceFolder((IFolder)container); - - // we get the delete on the folder before the file, so it is possible - // the associated ResourceFolder doesn't exist anymore. - if (resFolder != null) { - // remove the file - resFolder.removeFile(file); - } - } - } - break; - } - } - - public void projectClosed(IProject project) { - mMap.remove(project); - } - - public void projectDeleted(IProject project) { - mMap.remove(project); - } - - public void projectOpened(IProject project) { - createProject(project); - } - - public void projectOpenedWithWorkspace(IProject project) { - createProject(project); - } - - /** - * Returns the {@link ResourceFolder} for the given file or <code>null</code> if none exists. - */ - public ResourceFolder getResourceFolder(IFile file) { - IContainer container = file.getParent(); - if (container.getType() == IResource.FOLDER) { - IFolder parent = (IFolder)container; - IProject project = file.getProject(); - - ProjectResources resources = getProjectResources(project); - if (resources != null) { - return resources.getResourceFolder(parent); - } - } - - return null; - } - - /** - * Loads and returns the resources for a given {@link IAndroidTarget} - * @param androidTarget the target from which to load the framework resources - */ - public ProjectResources loadFrameworkResources(IAndroidTarget androidTarget) { - String osResourcesPath = androidTarget.getPath(IAndroidTarget.RESOURCES); - - File frameworkRes = new File(osResourcesPath); - if (frameworkRes.isDirectory()) { - ProjectResources resources = new ProjectResources(true /* isFrameworkRepository */); - - try { - File[] files = frameworkRes.listFiles(); - for (File file : files) { - if (file.isDirectory()) { - ResourceFolder resFolder = processFolder(new FolderWrapper(file), - resources); - - if (resFolder != null) { - // now we process the content of the folder - File[] children = file.listFiles(); - - for (File childRes : children) { - if (childRes.isFile()) { - processFile(new FileWrapper(childRes), resFolder); - } - } - } - - } - } - - // now that we have loaded the files, we need to force load the resources from them - resources.loadAll(); - - return resources; - - } catch (IOException e) { - // since we test that folders are folders, and files are files, this shouldn't - // happen. We can ignore it. - } - } - - return null; - } - - /** - * Initial project parsing to gather resource info. - * @param project - */ - private void createProject(IProject project) { - if (project.isOpen()) { - try { - if (project.hasNature(AndroidConstants.NATURE) == false) { - return; - } - } catch (CoreException e1) { - // can't check the nature of the project? ignore it. - return; - } - - IFolder resourceFolder = project.getFolder(SdkConstants.FD_RESOURCES); - - ProjectResources projectResources = mMap.get(project); - if (projectResources == null) { - projectResources = new ProjectResources(false /* isFrameworkRepository */); - mMap.put(project, projectResources); - } - - if (resourceFolder != null && resourceFolder.exists()) { - try { - IResource[] resources = resourceFolder.members(); - - for (IResource res : resources) { - if (res.getType() == IResource.FOLDER) { - IFolder folder = (IFolder)res; - ResourceFolder resFolder = processFolder(new IFolderWrapper(folder), - projectResources); - - if (resFolder != null) { - // now we process the content of the folder - IResource[] files = folder.members(); - - for (IResource fileRes : files) { - if (fileRes.getType() == IResource.FILE) { - IFile file = (IFile)fileRes; - - processFile(new IFileWrapper(file), resFolder); - } - } - } - } - } - } catch (CoreException e) { - // This happens if the project is closed or if the folder doesn't exist. - // Since we already test for that, we can ignore this exception. - } - } - } - } - - /** - * Creates a {@link FolderConfiguration} matching the folder segments. - * @param folderSegments The segments of the folder name. The first segments should contain - * the name of the folder - * @return a FolderConfiguration object, or null if the folder name isn't valid.. - */ - public FolderConfiguration getConfig(String[] folderSegments) { - FolderConfiguration config = new FolderConfiguration(); - - // we are going to loop through the segments, and match them with the first - // available qualifier. If the segment doesn't match we try with the next qualifier. - // Because the order of the qualifier is fixed, we do not reset the first qualifier - // after each sucessful segment. - // If we run out of qualifier before processing all the segments, we fail. - - int qualifierIndex = 0; - int qualifierCount = mQualifiers.length; - - for (int i = 1 ; i < folderSegments.length; i++) { - String seg = folderSegments[i]; - if (seg.length() > 0) { - while (qualifierIndex < qualifierCount && - mQualifiers[qualifierIndex].checkAndSet(seg, config) == false) { - qualifierIndex++; - } - - // if we reached the end of the qualifier we didn't find a matching qualifier. - if (qualifierIndex == qualifierCount) { - return null; - } - - } else { - return null; - } - } - - return config; - } - - /** - * Processes a folder and adds it to the list of the project resources. - * @param folder the folder to process - * @param project the folder's project. - * @return the ConfiguredFolder created from this folder, or null if the process failed. - */ - private ResourceFolder processFolder(IAbstractFolder folder, ProjectResources project) { - // split the name of the folder in segments. - String[] folderSegments = folder.getName().split(FolderConfiguration.QUALIFIER_SEP); - - // get the enum for the resource type. - ResourceFolderType type = ResourceFolderType.getTypeByName(folderSegments[0]); - - if (type != null) { - // get the folder configuration. - FolderConfiguration config = getConfig(folderSegments); - - if (config != null) { - ResourceFolder configuredFolder = project.add(type, config, folder); - - return configuredFolder; - } - } - - return null; - } - - /** - * Processes a file and adds it to its parent folder resource. - * @param file - * @param folder - */ - private void processFile(IAbstractFile file, ResourceFolder folder) { - // get the type of the folder - ResourceFolderType type = folder.getType(); - - // look for this file if it's already been created - ResourceFile resFile = folder.getFile(file); - - if (resFile != null) { - // invalidate the file - resFile.touch(); - } else { - // create a ResourceFile for it. - - // check if that's a single or multi resource type folder. For now we define this by - // the number of possible resource type output by files in the folder. This does - // not make the difference between several resource types from a single file or - // the ability to have 2 files in the same folder generating 2 different types of - // resource. The former is handled by MultiResourceFile properly while we don't - // handle the latter. If we were to add this behavior we'd have to change this call. - ResourceType[] types = FolderTypeRelationship.getRelatedResourceTypes(type); - - if (types.length == 1) { - resFile = new SingleResourceFile(file, folder); - } else { - resFile = new MultiResourceFile(file, folder); - } - - // add it to the folder - folder.addFile(resFile); - } - } - - /** - * Returns true if the path is under /project/res/ - * @param path a workspace relative path - * @return true if the path is under /project res/ - */ - private boolean isInResFolder(IPath path) { - return SdkConstants.FD_RESOURCES.equalsIgnoreCase(path.segment(1)); - } - - /** - * Private constructor to enforce singleton design. - */ - ResourceManager() { - // get the default qualifiers. - FolderConfiguration defaultConfig = new FolderConfiguration(); - defaultConfig.createDefault(); - mQualifiers = defaultConfig.getQualifiers(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java deleted file mode 100644 index 59a72fb..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.project.BaseProjectHelper; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceChangeEvent; -import org.eclipse.core.resources.IResourceChangeListener; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jdt.core.IJavaModel; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; - -import java.util.ArrayList; - -/** - * Resource Monitor for the whole editor plugin. Other, more simple, listeners can register to - * that one. - */ -public class ResourceMonitor implements IResourceChangeListener { - - private final static ResourceMonitor sThis = new ResourceMonitor(); - - /** - * Classes which implement this interface provide a method that deals - * with file change events. - */ - public interface IFileListener { - /** - * Sent when a file changed. - * @param file The file that changed. - * @param markerDeltas The marker deltas for the file. - * @param kind The change kind. This is equivalent to - * {@link IResourceDelta#accept(IResourceDeltaVisitor)} - */ - public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind); - } - - /** - * Classes which implements this interface provide methods dealing with project events. - */ - public interface IProjectListener { - /** - * Sent for each opened android project at the time the listener is put in place. - * @param project the opened project. - */ - public void projectOpenedWithWorkspace(IProject project); - /** - * Sent when a project is opened. - * @param project the project being opened. - */ - public void projectOpened(IProject project); - /** - * Sent when a project is closed. - * @param project the project being closed. - */ - public void projectClosed(IProject project); - /** - * Sent when a project is deleted. - * @param project the project about to be deleted. - */ - public void projectDeleted(IProject project); - } - - /** - * Classes which implement this interface provide a method that deals - * with folder change events - */ - public interface IFolderListener { - /** - * Sent when a folder changed. - * @param folder The file that was changed - * @param kind The change kind. This is equivalent to {@link IResourceDelta#getKind()} - */ - public void folderChanged(IFolder folder, int kind); - } - - /** - * Interface for a listener to be notified when resource change event starts and ends. - */ - public interface IResourceEventListener { - public void resourceChangeEventStart(); - public void resourceChangeEventEnd(); - } - - /** - * Base listener bundle to associate a listener to an event mask. - */ - private static class ListenerBundle { - /** Mask value to accept all events */ - public final static int MASK_NONE = -1; - - /** - * Event mask. Values accepted are IResourceDelta.### - * @see IResourceDelta#ADDED - * @see IResourceDelta#REMOVED - * @see IResourceDelta#CHANGED - * @see IResourceDelta#ADDED_PHANTOM - * @see IResourceDelta#REMOVED_PHANTOM - * */ - int kindMask; - } - - /** - * Listener bundle for file event. - */ - private static class FileListenerBundle extends ListenerBundle { - - /** The file listener */ - IFileListener listener; - } - - /** - * Listener bundle for folder event. - */ - private static class FolderListenerBundle extends ListenerBundle { - /** The file listener */ - IFolderListener listener; - } - - private final ArrayList<FileListenerBundle> mFileListeners = - new ArrayList<FileListenerBundle>(); - - private final ArrayList<FolderListenerBundle> mFolderListeners = - new ArrayList<FolderListenerBundle>(); - - private final ArrayList<IProjectListener> mProjectListeners = new ArrayList<IProjectListener>(); - - private final ArrayList<IResourceEventListener> mEventListeners = - new ArrayList<IResourceEventListener>(); - - private IWorkspace mWorkspace; - - /** - * Delta visitor for resource changes. - */ - private final class DeltaVisitor implements IResourceDeltaVisitor { - - public boolean visit(IResourceDelta delta) { - IResource r = delta.getResource(); - int type = r.getType(); - if (type == IResource.FILE) { - int kind = delta.getKind(); - // notify the listeners. - for (FileListenerBundle bundle : mFileListeners) { - if (bundle.kindMask == ListenerBundle.MASK_NONE - || (bundle.kindMask & kind) != 0) { - bundle.listener.fileChanged((IFile)r, delta.getMarkerDeltas(), kind); - } - } - return false; - } else if (type == IResource.FOLDER) { - int kind = delta.getKind(); - // notify the listeners. - for (FolderListenerBundle bundle : mFolderListeners) { - if (bundle.kindMask == ListenerBundle.MASK_NONE - || (bundle.kindMask & kind) != 0) { - bundle.listener.folderChanged((IFolder)r, kind); - } - } - return true; - } else if (type == IResource.PROJECT) { - int flags = delta.getFlags(); - - if (flags == IResourceDelta.OPEN) { - // the project is opening or closing. - IProject project = (IProject)r; - - if (project.isOpen()) { - // notify the listeners. - for (IProjectListener pl : mProjectListeners) { - pl.projectOpened(project); - } - } else { - // notify the listeners. - for (IProjectListener pl : mProjectListeners) { - pl.projectClosed(project); - } - } - } - } - - return true; - } - } - - public static ResourceMonitor getMonitor() { - return sThis; - } - - - /** - * Starts the resource monitoring. - * @param ws The current workspace. - * @return The monitor object. - */ - public static ResourceMonitor startMonitoring(IWorkspace ws) { - if (sThis != null) { - ws.addResourceChangeListener(sThis, - IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE); - sThis.mWorkspace = ws; - } - return sThis; - } - - /** - * Stops the resource monitoring. - * @param ws The current workspace. - */ - public static void stopMonitoring(IWorkspace ws) { - if (sThis != null) { - ws.removeResourceChangeListener(sThis); - - sThis.mFileListeners.clear(); - sThis.mProjectListeners.clear(); - } - } - - /** - * Adds a file listener. - * @param listener The listener to receive the events. - * @param kindMask The event mask to filter out specific events. - * {@link ListenerBundle#MASK_NONE} will forward all events. - */ - public synchronized void addFileListener(IFileListener listener, int kindMask) { - FileListenerBundle bundle = new FileListenerBundle(); - bundle.listener = listener; - bundle.kindMask = kindMask; - - mFileListeners.add(bundle); - } - - /** - * Removes an existing file listener. - * @param listener the listener to remove. - */ - public synchronized void removeFileListener(IFileListener listener) { - for (int i = 0 ; i < mFileListeners.size() ; i++) { - FileListenerBundle bundle = mFileListeners.get(i); - if (bundle.listener == listener) { - mFileListeners.remove(i); - return; - } - } - } - - /** - * Adds a folder listener. - * @param listener The listener to receive the events. - * @param kindMask The event mask to filter out specific events. - * {@link ListenerBundle#MASK_NONE} will forward all events. - */ - public synchronized void addFolderListener(IFolderListener listener, int kindMask) { - FolderListenerBundle bundle = new FolderListenerBundle(); - bundle.listener = listener; - bundle.kindMask = kindMask; - - mFolderListeners.add(bundle); - } - - /** - * Removes an existing folder listener. - * @param listener the listener to remove. - */ - public synchronized void removeFolderListener(IFolderListener listener) { - for (int i = 0 ; i < mFolderListeners.size() ; i++) { - FolderListenerBundle bundle = mFolderListeners.get(i); - if (bundle.listener == listener) { - mFolderListeners.remove(i); - return; - } - } - } - - /** - * Adds a project listener. - * @param listener The listener to receive the events. - */ - public synchronized void addProjectListener(IProjectListener listener) { - mProjectListeners.add(listener); - - // we need to look at the opened projects and give them to the listener. - - // get the list of opened android projects. - IWorkspaceRoot workspaceRoot = mWorkspace.getRoot(); - IJavaModel javaModel = JavaCore.create(workspaceRoot); - IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(javaModel); - - for (IJavaProject androidProject : androidProjects) { - listener.projectOpenedWithWorkspace(androidProject.getProject()); - } - } - - /** - * Removes an existing project listener. - * @param listener the listener to remove. - */ - public synchronized void removeProjectListener(IProjectListener listener) { - mProjectListeners.remove(listener); - } - - /** - * Adds a resource event listener. - * @param listener The listener to receive the events. - */ - public synchronized void addResourceEventListener(IResourceEventListener listener) { - mEventListeners.add(listener); - } - - /** - * Removes an existing Resource Event listener. - * @param listener the listener to remove. - */ - public synchronized void removeResourceEventListener(IResourceEventListener listener) { - mEventListeners.remove(listener); - } - - /** - * Processes the workspace resource change events. - */ - public void resourceChanged(IResourceChangeEvent event) { - // notify the event listeners of a start. - for (IResourceEventListener listener : mEventListeners) { - listener.resourceChangeEventStart(); - } - - if (event.getType() == IResourceChangeEvent.PRE_DELETE) { - // a project is being deleted. Lets get the project object and remove - // its compiled resource list. - IResource r = event.getResource(); - IProject project = r.getProject(); - - // notify the listeners. - for (IProjectListener pl : mProjectListeners) { - pl.projectDeleted(project); - } - } else { - // this a regular resource change. We get the delta and go through it with a visitor. - IResourceDelta delta = event.getDelta(); - - DeltaVisitor visitor = new DeltaVisitor(); - try { - delta.accept(visitor); - } catch (CoreException e) { - } - } - - // we're done, notify the event listeners. - for (IResourceEventListener listener : mEventListeners) { - listener.resourceChangeEventEnd(); - } - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java deleted file mode 100644 index 32b1107..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.manager; - -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFile; -import com.android.layoutlib.api.IResourceValue; -import com.android.layoutlib.utils.ResourceValue; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.parsers.SAXParserFactory; - -/** - * Represents a resource file describing a single resource. - * <p/> - * This is typically an XML file inside res/anim, res/layout, or res/menu or an image file - * under res/drawable. - */ -public class SingleResourceFile extends ResourceFile { - - private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance(); - static { - sParserFactory.setNamespaceAware(true); - } - - private final static Pattern sXmlPattern = Pattern.compile("^(.+)\\.xml", //$NON-NLS-1$ - Pattern.CASE_INSENSITIVE); - - private final static Pattern[] sDrawablePattern = new Pattern[] { - Pattern.compile("^(.+)\\.9\\.png", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$ - Pattern.compile("^(.+)\\.png", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$ - Pattern.compile("^(.+)\\.jpg", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$ - Pattern.compile("^(.+)\\.gif", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$ - }; - - private String mResourceName; - private ResourceType mType; - private IResourceValue mValue; - - public SingleResourceFile(IAbstractFile file, ResourceFolder folder) { - super(file, folder); - - // we need to infer the type of the resource from the folder type. - // This is easy since this is a single Resource file. - ResourceType[] types = FolderTypeRelationship.getRelatedResourceTypes(folder.getType()); - mType = types[0]; - - // compute the resource name - mResourceName = getResourceName(mType); - - mValue = new ResourceValue(mType.getName(), getResourceName(mType), file.getOsLocation(), - isFramework()); - } - - @Override - public ResourceType[] getResourceTypes() { - return FolderTypeRelationship.getRelatedResourceTypes(getFolder().getType()); - } - - @Override - public boolean hasResources(ResourceType type) { - return FolderTypeRelationship.match(type, getFolder().getType()); - } - - @Override - public Collection<ProjectResourceItem> getResources(ResourceType type, - ProjectResources projectResources) { - - // looking for an existing ResourceItem with this name and type - ProjectResourceItem item = projectResources.findResourceItem(type, mResourceName); - - ArrayList<ProjectResourceItem> items = new ArrayList<ProjectResourceItem>(); - - if (item == null) { - item = new ConfigurableResourceItem(mResourceName); - items.add(item); - } - - // add this ResourceFile to the ResourceItem - item.add(this); - - return items; - } - - /* - * (non-Javadoc) - * @see com.android.ide.eclipse.editors.resources.manager.ResourceFile#getValue(com.android.ide.eclipse.common.resources.ResourceType, java.lang.String) - * - * This particular implementation does not care about the type or name since a - * SingleResourceFile represents a file generating only one resource. - * The value returned is the full absolute path of the file in OS form. - */ - @Override - public IResourceValue getValue(ResourceType type, String name) { - return mValue; - } - - /** - * Returns the name of the resources. - */ - private String getResourceName(ResourceType type) { - // get the name from the filename. - String name = getFile().getName(); - - if (type == ResourceType.ANIM || type == ResourceType.LAYOUT || type == ResourceType.MENU || - type == ResourceType.COLOR || type == ResourceType.XML) { - Matcher m = sXmlPattern.matcher(name); - if (m.matches()) { - return m.group(1); - } - } else if (type == ResourceType.DRAWABLE) { - for (Pattern p : sDrawablePattern) { - Matcher m = p.matcher(name); - if (m.matches()) { - return m.group(1); - } - } - - // also try the Xml pattern for selector/shape based drawable. - Matcher m = sXmlPattern.matcher(name); - if (m.matches()) { - return m.group(1); - } - } - return name; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java deleted file mode 100644 index d99cb13..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFile; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -/** - * An implementation of {@link IAbstractFile} on top of a {@link File} object. - * - */ -public class FileWrapper implements IAbstractFile { - - private File mFile; - - /** - * Constructs a {@link FileWrapper} object. If {@link File#isFile()} returns <code>false</code> - * then an {@link IOException} is thrown. - */ - public FileWrapper(File file) throws IOException { - if (file.isFile() == false) { - throw new IOException("FileWrapper must wrap a File object representing an existing file!"); //$NON-NLS-1$ - } - - mFile = file; - } - - public InputStream getContents() { - try { - return new FileInputStream(mFile); - } catch (FileNotFoundException e) { - // we'll return null below. - } - - return null; - } - - public IFile getIFile() { - return null; - } - - public String getOsLocation() { - return mFile.getAbsolutePath(); - } - - public String getName() { - return mFile.getName(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof FileWrapper) { - return mFile.equals(((FileWrapper)obj).mFile); - } - - if (obj instanceof File) { - return mFile.equals(obj); - } - - return super.equals(obj); - } - - @Override - public int hashCode() { - return mFile.hashCode(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java deleted file mode 100644 index 9ad7460..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFolder; - -import java.io.File; -import java.io.IOException; - -/** - * An implementation of {@link IAbstractFolder} on top of a {@link File} object. - */ -public class FolderWrapper implements IAbstractFolder { - - private File mFolder; - - /** - * Constructs a {@link FileWrapper} object. If {@link File#isDirectory()} returns - * <code>false</code> then an {@link IOException} is thrown. - */ - public FolderWrapper(File folder) throws IOException { - if (folder.isDirectory() == false) { - throw new IOException("FileWrapper must wrap a File object representing an existing folder!"); //$NON-NLS-1$ - } - - mFolder = folder; - } - - public boolean hasFile(String name) { - return false; - } - - public String getName() { - return mFolder.getName(); - } - - public IFolder getIFolder() { - return null; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof FolderWrapper) { - return mFolder.equals(((FolderWrapper)obj).mFolder); - } - - if (obj instanceof File) { - return mFolder.equals(obj); - } - - return super.equals(obj); - } - - @Override - public int hashCode() { - return mFolder.hashCode(); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractFile.java deleted file mode 100644 index 7e807f9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractFile.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.CoreException; - -import java.io.InputStream; - -/** - * A file. - */ -public interface IAbstractFile extends IAbstractResource { - - /** - * Returns an {@link InputStream} object on the file content. - * @throws CoreException - */ - InputStream getContents() throws CoreException; - - /** - * Returns the OS path of the file location. - */ - String getOsLocation(); - - /** - * Returns the {@link IFile} object that the receiver could represent. Can be <code>null</code> - */ - IFile getIFile(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractFolder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractFolder.java deleted file mode 100644 index b35283d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractFolder.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFolder; - -/** - * A folder. - */ -public interface IAbstractFolder extends IAbstractResource { - - /** - * Returns true if the receiver contains a file with a given name - * @param name the name of the file. This is the name without the path leading to the - * parent folder. - */ - boolean hasFile(String name); - - /** - * Returns the {@link IFolder} object that the receiver could represent. - * Can be <code>null</code> - */ - IFolder getIFolder(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractResource.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractResource.java deleted file mode 100644 index daf243d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IAbstractResource.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFile; - -import java.io.File; - -/** - * Base representation of a file system resource.<p/> - * This somewhat limited interface is designed to let classes use file-system resources, without - * having the manually handle {@link IFile} and/or {@link File} manually. - */ -public interface IAbstractResource { - - /** - * Returns the name of the resource. - */ - String getName(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java deleted file mode 100644 index f0f5f2d..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.CoreException; - -import java.io.InputStream; - -/** - * An implementation of {@link IAbstractFile} on top of an {@link IFile} object. - */ -public class IFileWrapper implements IAbstractFile { - - private IFile mFile; - - public IFileWrapper(IFile file) { - mFile = file; - } - - public InputStream getContents() throws CoreException { - return mFile.getContents(); - } - - public String getOsLocation() { - return mFile.getLocation().toOSString(); - } - - public String getName() { - return mFile.getName(); - } - - public IFile getIFile() { - return mFile; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof IFileWrapper) { - return mFile.equals(((IFileWrapper)obj).mFile); - } - - if (obj instanceof IFile) { - return mFile.equals(obj); - } - - return super.equals(obj); - } - - @Override - public int hashCode() { - return mFile.hashCode(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java deleted file mode 100644 index b1fa3ef..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.manager.files; - -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; - -/** - * An implementation of {@link IAbstractFolder} on top of an {@link IFolder} object. - */ -public class IFolderWrapper implements IAbstractFolder { - - private IFolder mFolder; - - public IFolderWrapper(IFolder folder) { - mFolder = folder; - } - - public String getName() { - return mFolder.getName(); - } - - public boolean hasFile(String name) { - try { - IResource[] files = mFolder.members(); - for (IResource file : files) { - if (name.equals(file.getName())) { - return true; - } - } - } catch (CoreException e) { - // we'll return false below. - } - - return false; - } - - public IFolder getIFolder() { - return mFolder; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof IFolderWrapper) { - return mFolder.equals(((IFolderWrapper)obj).mFolder); - } - - if (obj instanceof IFolder) { - return mFolder.equals(obj); - } - - return super.equals(obj); - } - - @Override - public int hashCode() { - return mFolder.hashCode(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/uimodel/UiColorValueNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/uimodel/UiColorValueNode.java deleted file mode 100644 index 29453e9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/uimodel/UiColorValueNode.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.resources.uimodel; - -import com.android.ide.eclipse.editors.descriptors.TextValueDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.uimodel.UiTextValueNode; - -import org.eclipse.jface.dialogs.IMessageProvider; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.widgets.Text; - -import java.util.regex.Pattern; - -/** - * Displays and edits a color XML element value with a custom validator. - * <p/> - * See {@link UiAttributeNode} for more information. - */ -public class UiColorValueNode extends UiTextValueNode { - - /** Accepted RGBA formats are one of #RGB, #ARGB, #RRGGBB or #AARRGGBB. */ - private static final Pattern RGBA_REGEXP = Pattern.compile( - "#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})"); //$NON-NLS-1$ - - public UiColorValueNode(TextValueDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /* (non-java doc) - * - * Add a modify listener that will check colors have the proper format, - * that is one of #RGB, #ARGB, #RRGGBB or #AARRGGBB. - */ - @Override - protected void onAddValidators(final Text text) { - ModifyListener listener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - String color = text.getText(); - if (RGBA_REGEXP.matcher(color).matches()) { - getManagedForm().getMessageManager().removeMessage(text, text); - } else { - getManagedForm().getMessageManager().addMessage(text, - "Accepted color formats are one of #RGB, #ARGB, #RRGGBB or #AARRGGBB.", - null /* data */, IMessageProvider.ERROR, text); - } - } - }; - - text.addModifyListener(listener); - - // Make sure the validator removes its message(s) when the widget is disposed - text.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - getManagedForm().getMessageManager().removeMessage(text, text); - } - }); - - // Finally call the validator once to make sure the initial value is processed - listener.modifyText(null); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/uimodel/UiItemElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/uimodel/UiItemElementNode.java deleted file mode 100644 index 89649f5..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/uimodel/UiItemElementNode.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.resources.uimodel; - -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.resources.descriptors.ItemElementDescriptor; -import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * {@link UiItemElementNode} is apecial version of {@link UiElementNode} that - * customizes the element display to include the item type attribute if present. - */ -public class UiItemElementNode extends UiElementNode { - - /** - * Creates a new {@link UiElementNode} described by a given {@link ItemElementDescriptor}. - * - * @param elementDescriptor The {@link ItemElementDescriptor} for the XML node. Cannot be null. - */ - public UiItemElementNode(ItemElementDescriptor elementDescriptor) { - super(elementDescriptor); - } - - @Override - public String getShortDescription() { - Node xmlNode = getXmlNode(); - if (xmlNode != null && xmlNode instanceof Element && xmlNode.hasAttributes()) { - - Element elem = (Element) xmlNode; - String type = elem.getAttribute(ResourcesDescriptors.TYPE_ATTR); - String name = elem.getAttribute(ResourcesDescriptors.NAME_ATTR); - if (type != null && name != null && type.length() > 0 && name.length() > 0) { - type = DescriptorsUtils.capitalize(type); - return String.format("%1$s (%2$s %3$s)", name, type, getDescriptor().getUiName()); - } - } - - return super.getShortDescription(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/EditableDialogCellEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/EditableDialogCellEditor.java deleted file mode 100644 index 5fb479f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/EditableDialogCellEditor.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.jface.viewers.DialogCellEditor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusAdapter; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.KeyAdapter; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.MouseAdapter; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.TraverseEvent; -import org.eclipse.swt.events.TraverseListener; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Text; - -import java.text.MessageFormat; - -/** - * Custom DialogCellEditor, replacing the Label with an editable {@link Text} widget. - * <p/>Also set the button to {@link SWT#FLAT} to make sure it looks good on MacOS X. - * <p/>Most of the code comes from TextCellEditor. - */ -public abstract class EditableDialogCellEditor extends DialogCellEditor { - - private Text text; - - private ModifyListener modifyListener; - - /** - * State information for updating action enablement - */ - private boolean isSelection = false; - - private boolean isDeleteable = false; - - private boolean isSelectable = false; - - EditableDialogCellEditor(Composite parent) { - super(parent); - } - - /* - * Re-implement this method only to properly set the style in the button, or it won't look - * good in MacOS X - */ - @Override - protected Button createButton(Composite parent) { - Button result = new Button(parent, SWT.DOWN | SWT.FLAT); - result.setText("..."); //$NON-NLS-1$ - return result; - } - - - @Override - protected Control createContents(Composite cell) { - text = new Text(cell, SWT.SINGLE); - text.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetDefaultSelected(SelectionEvent e) { - handleDefaultSelection(e); - } - }); - text.addKeyListener(new KeyAdapter() { - // hook key pressed - see PR 14201 - @Override - public void keyPressed(KeyEvent e) { - keyReleaseOccured(e); - - // as a result of processing the above call, clients may have - // disposed this cell editor - if ((getControl() == null) || getControl().isDisposed()) { - return; - } - checkSelection(); // see explanation below - checkDeleteable(); - checkSelectable(); - } - }); - text.addTraverseListener(new TraverseListener() { - public void keyTraversed(TraverseEvent e) { - if (e.detail == SWT.TRAVERSE_ESCAPE - || e.detail == SWT.TRAVERSE_RETURN) { - e.doit = false; - } - } - }); - // We really want a selection listener but it is not supported so we - // use a key listener and a mouse listener to know when selection changes - // may have occurred - text.addMouseListener(new MouseAdapter() { - @Override - public void mouseUp(MouseEvent e) { - checkSelection(); - checkDeleteable(); - checkSelectable(); - } - }); - text.addFocusListener(new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - EditableDialogCellEditor.this.focusLost(); - } - }); - text.setFont(cell.getFont()); - text.setBackground(cell.getBackground()); - text.setText("");//$NON-NLS-1$ - text.addModifyListener(getModifyListener()); - return text; - } - - /** - * Checks to see if the "deletable" state (can delete/ - * nothing to delete) has changed and if so fire an - * enablement changed notification. - */ - private void checkDeleteable() { - boolean oldIsDeleteable = isDeleteable; - isDeleteable = isDeleteEnabled(); - if (oldIsDeleteable != isDeleteable) { - fireEnablementChanged(DELETE); - } - } - - /** - * Checks to see if the "selectable" state (can select) - * has changed and if so fire an enablement changed notification. - */ - private void checkSelectable() { - boolean oldIsSelectable = isSelectable; - isSelectable = isSelectAllEnabled(); - if (oldIsSelectable != isSelectable) { - fireEnablementChanged(SELECT_ALL); - } - } - - /** - * Checks to see if the selection state (selection / - * no selection) has changed and if so fire an - * enablement changed notification. - */ - private void checkSelection() { - boolean oldIsSelection = isSelection; - isSelection = text.getSelectionCount() > 0; - if (oldIsSelection != isSelection) { - fireEnablementChanged(COPY); - fireEnablementChanged(CUT); - } - } - - /* (non-Javadoc) - * Method declared on CellEditor. - */ - @Override - protected void doSetFocus() { - if (text != null) { - text.selectAll(); - text.setFocus(); - checkSelection(); - checkDeleteable(); - checkSelectable(); - } - } - - /* - * (non-Javadoc) - * @see org.eclipse.jface.viewers.DialogCellEditor#updateContents(java.lang.Object) - */ - @Override - protected void updateContents(Object value) { - Assert.isTrue(text != null && (value == null || (value instanceof String))); - if (value != null) { - text.removeModifyListener(getModifyListener()); - text.setText((String) value); - text.addModifyListener(getModifyListener()); - } - } - - /** - * The <code>TextCellEditor</code> implementation of - * this <code>CellEditor</code> framework method returns - * the text string. - * - * @return the text string - */ - @Override - protected Object doGetValue() { - return text.getText(); - } - - - /** - * Processes a modify event that occurred in this text cell editor. - * This framework method performs validation and sets the error message - * accordingly, and then reports a change via <code>fireEditorValueChanged</code>. - * Subclasses should call this method at appropriate times. Subclasses - * may extend or reimplement. - * - * @param e the SWT modify event - */ - protected void editOccured(ModifyEvent e) { - String value = text.getText(); - if (value == null) { - value = "";//$NON-NLS-1$ - } - Object typedValue = value; - boolean oldValidState = isValueValid(); - boolean newValidState = isCorrect(typedValue); - - if (!newValidState) { - // try to insert the current value into the error message. - setErrorMessage(MessageFormat.format(getErrorMessage(), - new Object[] { value })); - } - valueChanged(oldValidState, newValidState); - } - - /** - * Return the modify listener. - */ - private ModifyListener getModifyListener() { - if (modifyListener == null) { - modifyListener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - editOccured(e); - } - }; - } - return modifyListener; - } - - /** - * Handles a default selection event from the text control by applying the editor - * value and deactivating this cell editor. - * - * @param event the selection event - * - * @since 3.0 - */ - protected void handleDefaultSelection(SelectionEvent event) { - // same with enter-key handling code in keyReleaseOccured(e); - fireApplyEditorValue(); - deactivate(); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method returns <code>true</code> if - * the current selection is not empty. - */ - @Override - public boolean isCopyEnabled() { - if (text == null || text.isDisposed()) { - return false; - } - return text.getSelectionCount() > 0; - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method returns <code>true</code> if - * the current selection is not empty. - */ - @Override - public boolean isCutEnabled() { - if (text == null || text.isDisposed()) { - return false; - } - return text.getSelectionCount() > 0; - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method returns <code>true</code> - * if there is a selection or if the caret is not positioned - * at the end of the text. - */ - @Override - public boolean isDeleteEnabled() { - if (text == null || text.isDisposed()) { - return false; - } - return text.getSelectionCount() > 0 - || text.getCaretPosition() < text.getCharCount(); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method always returns <code>true</code>. - */ - @Override - public boolean isPasteEnabled() { - if (text == null || text.isDisposed()) { - return false; - } - return true; - } - - /** - * Check if save all is enabled - * @return true if it is - */ - public boolean isSaveAllEnabled() { - if (text == null || text.isDisposed()) { - return false; - } - return true; - } - - /** - * Returns <code>true</code> if this cell editor is - * able to perform the select all action. - * <p> - * This default implementation always returns - * <code>false</code>. - * </p> - * <p> - * Subclasses may override - * </p> - * @return <code>true</code> if select all is possible, - * <code>false</code> otherwise - */ - @Override - public boolean isSelectAllEnabled() { - if (text == null || text.isDisposed()) { - return false; - } - return text.getCharCount() > 0; - } - - /** - * Processes a key release event that occurred in this cell editor. - * <p> - * The <code>TextCellEditor</code> implementation of this framework method - * ignores when the RETURN key is pressed since this is handled in - * <code>handleDefaultSelection</code>. - * An exception is made for Ctrl+Enter for multi-line texts, since - * a default selection event is not sent in this case. - * </p> - * - * @param keyEvent the key event - */ - @Override - protected void keyReleaseOccured(KeyEvent keyEvent) { - if (keyEvent.character == '\r') { // Return key - // Enter is handled in handleDefaultSelection. - // Do not apply the editor value in response to an Enter key event - // since this can be received from the IME when the intent is -not- - // to apply the value. - // See bug 39074 [CellEditors] [DBCS] canna input mode fires bogus event from Text Control - // - // An exception is made for Ctrl+Enter for multi-line texts, since - // a default selection event is not sent in this case. - if (text != null && !text.isDisposed() - && (text.getStyle() & SWT.MULTI) != 0) { - if ((keyEvent.stateMask & SWT.CTRL) != 0) { - super.keyReleaseOccured(keyEvent); - } - } - return; - } - super.keyReleaseOccured(keyEvent); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method copies the - * current selection to the clipboard. - */ - @Override - public void performCopy() { - text.copy(); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method cuts the - * current selection to the clipboard. - */ - @Override - public void performCut() { - text.cut(); - checkSelection(); - checkDeleteable(); - checkSelectable(); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method deletes the - * current selection or, if there is no selection, - * the character next character from the current position. - */ - @Override - public void performDelete() { - if (text.getSelectionCount() > 0) { - // remove the contents of the current selection - text.insert(""); //$NON-NLS-1$ - } else { - // remove the next character - int pos = text.getCaretPosition(); - if (pos < text.getCharCount()) { - text.setSelection(pos, pos + 1); - text.insert(""); //$NON-NLS-1$ - } - } - checkSelection(); - checkDeleteable(); - checkSelectable(); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method pastes the - * the clipboard contents over the current selection. - */ - @Override - public void performPaste() { - text.paste(); - checkSelection(); - checkDeleteable(); - checkSelectable(); - } - - /** - * The <code>TextCellEditor</code> implementation of this - * <code>CellEditor</code> method selects all of the - * current text. - */ - @Override - public void performSelectAll() { - text.selectAll(); - checkSelection(); - checkDeleteable(); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ErrorImageComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ErrorImageComposite.java deleted file mode 100644 index d095376..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ErrorImageComposite.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.android.ide.eclipse.editors.ui; - -import org.eclipse.jface.resource.CompositeImageDescriptor; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.DecorationOverlayIcon; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; - -/** - * ImageDescriptor that adds a error marker. - * Based on {@link DecorationOverlayIcon} only available in Eclipse 3.3 - */ -public class ErrorImageComposite extends CompositeImageDescriptor { - - private Image mBaseImage; - private ImageDescriptor mErrorImageDescriptor; - private Point mSize; - - public ErrorImageComposite(Image baseImage) { - mBaseImage = baseImage; - mErrorImageDescriptor = PlatformUI.getWorkbench().getSharedImages().getImageDescriptor( - ISharedImages.IMG_OBJS_ERROR_TSK); - mSize = new Point(baseImage.getBounds().width, baseImage.getBounds().height); - } - - @Override - protected void drawCompositeImage(int width, int height) { - ImageData baseData = mBaseImage.getImageData(); - drawImage(baseData, 0, 0); - - ImageData overlayData = mErrorImageDescriptor.getImageData(); - if (overlayData.width == baseData.width && baseData.height == baseData.height) { - overlayData = overlayData.scaledTo(14, 14); - drawImage(overlayData, -3, mSize.y - overlayData.height + 3); - } else { - drawImage(overlayData, 0, mSize.y - overlayData.height); - } - } - - @Override - protected Point getSize() { - return mSize; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/FlagValueCellEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/FlagValueCellEditor.java deleted file mode 100644 index ccae099..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/FlagValueCellEditor.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui; - -import com.android.ide.eclipse.editors.uimodel.UiFlagAttributeNode; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -/** - * DialogCellEditor able to receive a {@link UiFlagAttributeNode} in the {@link #setValue(Object)} - * method. - * <p/>The dialog box opened is the same as the one in the ui created by - * {@link UiFlagAttributeNode#createUiControl(Composite, org.eclipse.ui.forms.IManagedForm)} - */ -public class FlagValueCellEditor extends EditableDialogCellEditor { - - private UiFlagAttributeNode mUiFlagAttribute; - - public FlagValueCellEditor(Composite parent) { - super(parent); - } - - @Override - protected Object openDialogBox(Control cellEditorWindow) { - if (mUiFlagAttribute != null) { - String currentValue = (String)getValue(); - return mUiFlagAttribute.showDialog(cellEditorWindow.getShell(), currentValue); - } - - return null; - } - - @Override - protected void doSetValue(Object value) { - if (value instanceof UiFlagAttributeNode) { - mUiFlagAttribute = (UiFlagAttributeNode)value; - super.doSetValue(mUiFlagAttribute.getCurrentValue()); - return; - } - - super.doSetValue(value); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ListValueCellEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ListValueCellEditor.java deleted file mode 100644 index 304dd14..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ListValueCellEditor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui; - -import com.android.ide.eclipse.editors.uimodel.UiListAttributeNode; - -import org.eclipse.jface.viewers.ComboBoxCellEditor; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.CCombo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -/** - * ComboBoxCellEditor able to receive a {@link UiListAttributeNode} in the {@link #setValue(Object)} - * method, and returning a {@link String} in {@link #getValue()} instead of an {@link Integer}. - */ -public class ListValueCellEditor extends ComboBoxCellEditor { - private String[] mItems; - private CCombo mCombo; - - public ListValueCellEditor(Composite parent) { - super(parent, new String[0], SWT.DROP_DOWN); - } - - @Override - protected Control createControl(Composite parent) { - mCombo = (CCombo) super.createControl(parent); - return mCombo; - } - - @Override - protected void doSetValue(Object value) { - if (value instanceof UiListAttributeNode) { - UiListAttributeNode uiListAttribute = (UiListAttributeNode)value; - - // set the possible values in the combo - String[] items = uiListAttribute.getPossibleValues(); - mItems = new String[items.length]; - System.arraycopy(items, 0, mItems, 0, items.length); - setItems(mItems); - - // now edit the current value of the attribute - String attrValue = uiListAttribute.getCurrentValue(); - mCombo.setText(attrValue); - - return; - } - - // default behavior - super.doSetValue(value); - } - - @Override - protected Object doGetValue() { - String comboText = mCombo.getText(); - if (comboText == null) { - return ""; //$NON-NLS-1$ - } - return comboText; - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ResourceValueCellEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ResourceValueCellEditor.java deleted file mode 100644 index 4fc0ab3..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/ResourceValueCellEditor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui; - -import com.android.ide.eclipse.editors.uimodel.UiFlagAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiResourceAttributeNode; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; - -/** - * DialogCellEditor able to receive a {@link UiFlagAttributeNode} in the {@link #setValue(Object)} - * method. - * <p/>The dialog box opened is the same as the one in the ui created by - * {@link UiFlagAttributeNode#createUiControl(Composite, org.eclipse.ui.forms.IManagedForm)} - */ -public class ResourceValueCellEditor extends EditableDialogCellEditor { - - private UiResourceAttributeNode mUiResourceAttribute; - - public ResourceValueCellEditor(Composite parent) { - super(parent); - } - - @Override - protected Object openDialogBox(Control cellEditorWindow) { - if (mUiResourceAttribute != null) { - String currentValue = (String)getValue(); - return mUiResourceAttribute.showDialog(cellEditorWindow.getShell(), currentValue); - } - - return null; - } - - @Override - protected void doSetValue(Object value) { - if (value instanceof UiResourceAttributeNode) { - mUiResourceAttribute = (UiResourceAttributeNode)value; - super.doSetValue(mUiResourceAttribute.getCurrentValue()); - return; - } - - super.doSetValue(value); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/SectionHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/SectionHelper.java deleted file mode 100644 index 409e92f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/SectionHelper.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.AndroidEditor; - -import org.eclipse.jface.text.DefaultInformationControl; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseTrackListener; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.SectionPart; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.eclipse.ui.forms.widgets.TableWrapLayout; - -import java.lang.reflect.Method; - -/** - * Helper for the AndroidManifest form editor. - * - * Helps create a new SectionPart with sensible default parameters, - * create default layout or add typical widgets. - * - * IMPORTANT: This is NOT a generic class. It makes a lot of assumptions on the - * UI as used by the form editor for the AndroidManifest. - * - * TODO: Consider moving to a common package. - */ -public final class SectionHelper { - - /** - * Utility class that derives from SectionPart, constructs the Section with - * sensible defaults (with a title and a description) and provide some shorthand - * methods for creating typically UI (label and text, form text.) - */ - static public class ManifestSectionPart extends SectionPart { - - /** - * Construct a SectionPart that uses a title bar and a description. - * It's up to the caller to call setText() and setDescription(). - * <p/> - * The section style includes a description and a title bar by default. - * - * @param body The parent (e.g. FormPage body) - * @param toolkit Form Toolkit - */ - public ManifestSectionPart(Composite body, FormToolkit toolkit) { - this(body, toolkit, 0, false); - } - - /** - * Construct a SectionPart that uses a title bar and a description. - * It's up to the caller to call setText() and setDescription(). - * <p/> - * The section style includes a description and a title bar by default. - * You can add extra styles, like Section.TWISTIE. - * - * @param body The parent (e.g. FormPage body). - * @param toolkit Form Toolkit. - * @param extra_style Extra styles (on top of description and title bar). - * @param use_description True if the Section.DESCRIPTION style should be added. - */ - public ManifestSectionPart(Composite body, FormToolkit toolkit, - int extra_style, boolean use_description) { - super(body, toolkit, extra_style | - Section.TITLE_BAR | - (use_description ? Section.DESCRIPTION : 0)); - } - - // Create non-static methods of helpers just for convenience - - /** - * Creates a new composite with a TableWrapLayout set with a given number of columns. - * - * If the parent composite is a Section, the new composite is set as a client. - * - * @param toolkit Form Toolkit - * @param numColumns Desired number of columns. - * @return The new composite. - */ - public Composite createTableLayout(FormToolkit toolkit, int numColumns) { - return SectionHelper.createTableLayout(getSection(), toolkit, numColumns); - } - - /** - * Creates a label widget. - * If the parent layout if a TableWrapLayout, maximize it to span over all columns. - * - * @param parent The parent (e.g. composite from CreateTableLayout()) - * @param toolkit Form Toolkit - * @param label The string for the label. - * @param tooltip An optional tooltip for the label and text. Can be null. - * @return The new created label - */ - public Label createLabel(Composite parent, FormToolkit toolkit, String label, - String tooltip) { - return SectionHelper.createLabel(parent, toolkit, label, tooltip); - } - - /** - * Creates two widgets: a label and a text field. - * - * This expects the parent composite to have a TableWrapLayout with 2 columns. - * - * @param parent The parent (e.g. composite from CreateTableLayout()) - * @param toolkit Form Toolkit - * @param label The string for the label. - * @param value The initial value of the text field. Can be null. - * @param tooltip An optional tooltip for the label and text. Can be null. - * @return The new created Text field (the label is not returned) - */ - public Text createLabelAndText(Composite parent, FormToolkit toolkit, String label, - String value, String tooltip) { - return SectionHelper.createLabelAndText(parent, toolkit, label, value, tooltip); - } - - /** - * Creates a FormText widget. - * - * This expects the parent composite to have a TableWrapLayout with 2 columns. - * - * @param parent The parent (e.g. composite from CreateTableLayout()) - * @param toolkit Form Toolkit - * @param isHtml True if the form text will contain HTML that must be interpreted as - * rich text (i.e. parse tags & expand URLs). - * @param label The string for the label. - * @param setupLayoutData indicates whether the created form text receives a TableWrapData - * through the setLayoutData method. In some case, creating it will make the table parent - * huge, which we don't want. - * @return The new created FormText. - */ - public FormText createFormText(Composite parent, FormToolkit toolkit, boolean isHtml, - String label, boolean setupLayoutData) { - return SectionHelper.createFormText(parent, toolkit, isHtml, label, setupLayoutData); - } - - /** - * Forces the section to recompute its layout and redraw. - * This is needed after the content of the section has been changed at runtime. - */ - public void layoutChanged() { - Section section = getSection(); - - // Calls getSection().reflow(), which is the same that Section calls - // when the expandable state is changed and the height changes. - // Since this is protected, some reflection is needed to invoke it. - try { - Method reflow; - reflow = section.getClass().getDeclaredMethod("reflow", (Class<?>[])null); - reflow.setAccessible(true); - reflow.invoke(section); - } catch (Exception e) { - AdtPlugin.log(e, "Error when invoking Section.reflow"); - } - - section.layout(true /* changed */, true /* all */); - } - } - - /** - * Creates a new composite with a TableWrapLayout set with a given number of columns. - * - * If the parent composite is a Section, the new composite is set as a client. - * - * @param composite The parent (e.g. a Section or SectionPart) - * @param toolkit Form Toolkit - * @param numColumns Desired number of columns. - * @return The new composite. - */ - static public Composite createTableLayout(Composite composite, FormToolkit toolkit, - int numColumns) { - Composite table = toolkit.createComposite(composite); - TableWrapLayout layout = new TableWrapLayout(); - layout.numColumns = numColumns; - table.setLayout(layout); - toolkit.paintBordersFor(table); - if (composite instanceof Section) { - ((Section) composite).setClient(table); - } - return table; - } - - /** - * Creates a new composite with a GridLayout set with a given number of columns. - * - * If the parent composite is a Section, the new composite is set as a client. - * - * @param composite The parent (e.g. a Section or SectionPart) - * @param toolkit Form Toolkit - * @param numColumns Desired number of columns. - * @return The new composite. - */ - static public Composite createGridLayout(Composite composite, FormToolkit toolkit, - int numColumns) { - Composite grid = toolkit.createComposite(composite); - GridLayout layout = new GridLayout(); - layout.numColumns = numColumns; - grid.setLayout(layout); - toolkit.paintBordersFor(grid); - if (composite instanceof Section) { - ((Section) composite).setClient(grid); - } - return grid; - } - - /** - * Creates two widgets: a label and a text field. - * - * This expects the parent composite to have a TableWrapLayout with 2 columns. - * - * @param parent The parent (e.g. composite from CreateTableLayout()) - * @param toolkit Form Toolkit - * @param label_text The string for the label. - * @param value The initial value of the text field. Can be null. - * @param tooltip An optional tooltip for the label and text. Can be null. - * @return The new created Text field (the label is not returned) - */ - static public Text createLabelAndText(Composite parent, FormToolkit toolkit, String label_text, - String value, String tooltip) { - Label label = toolkit.createLabel(parent, label_text); - label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - Text text = toolkit.createText(parent, value); - text.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); - - addControlTooltip(label, tooltip); - return text; - } - - /** - * Creates a label widget. - * If the parent layout if a TableWrapLayout, maximize it to span over all columns. - * - * @param parent The parent (e.g. composite from CreateTableLayout()) - * @param toolkit Form Toolkit - * @param label_text The string for the label. - * @param tooltip An optional tooltip for the label and text. Can be null. - * @return The new created label - */ - static public Label createLabel(Composite parent, FormToolkit toolkit, String label_text, - String tooltip) { - Label label = toolkit.createLabel(parent, label_text); - - TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB); - if (parent.getLayout() instanceof TableWrapLayout) { - twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns; - } - label.setLayoutData(twd); - - addControlTooltip(label, tooltip); - return label; - } - - /** - * Associates a tooltip with a control. - * - * This mirrors the behavior from org.eclipse.pde.internal.ui.editor.text.PDETextHover - * - * @param control The control to which associate the tooltip. - * @param tooltip The tooltip string. Can use \n for multi-lines. Will not display if null. - */ - static public void addControlTooltip(final Control control, String tooltip) { - if (control == null || tooltip == null || tooltip.length() == 0) { - return; - } - - // Some kinds of controls already properly implement tooltip display. - if (control instanceof Button) { - control.setToolTipText(tooltip); - return; - } - - control.setToolTipText(null); - - final DefaultInformationControl ic = new DefaultInformationControl(control.getShell()); - ic.setInformation(tooltip); - Point sz = ic.computeSizeHint(); - ic.setSize(sz.x, sz.y); - ic.setVisible(false); // initially hidden - - control.addMouseTrackListener(new MouseTrackListener() { - public void mouseEnter(MouseEvent e) { - } - - public void mouseExit(MouseEvent e) { - ic.setVisible(false); - } - - public void mouseHover(MouseEvent e) { - ic.setLocation(control.toDisplay(10, 25)); // same offset as in PDETextHover - ic.setVisible(true); - } - }); - } - - /** - * Creates a FormText widget. - * - * This expects the parent composite to have a TableWrapLayout with 2 columns. - * - * @param parent The parent (e.g. composite from CreateTableLayout()) - * @param toolkit Form Toolkit - * @param isHtml True if the form text will contain HTML that must be interpreted as - * rich text (i.e. parse tags & expand URLs). - * @param label The string for the label. - * @param setupLayoutData indicates whether the created form text receives a TableWrapData - * through the setLayoutData method. In some case, creating it will make the table parent - * huge, which we don't want. - * @return The new created FormText. - */ - static public FormText createFormText(Composite parent, FormToolkit toolkit, - boolean isHtml, String label, boolean setupLayoutData) { - FormText text = toolkit.createFormText(parent, true /* track focus */); - if (setupLayoutData) { - TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.maxWidth = AndroidEditor.TEXT_WIDTH_HINT; - if (parent.getLayout() instanceof TableWrapLayout) { - twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns; - } - text.setLayoutData(twd); - } - text.setWhitespaceNormalized(true); - text.setText(label, isHtml /* parseTags */, isHtml /* expandURLs */); - return text; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/TextValueCellEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/TextValueCellEditor.java deleted file mode 100644 index 2fe5783..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/TextValueCellEditor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui; - -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; - -import org.eclipse.jface.viewers.TextCellEditor; -import org.eclipse.swt.widgets.Composite; - -/** - * TextCellEditor able to receive a {@link UiAttributeNode} in the {@link #setValue(Object)} - * method. - */ -public class TextValueCellEditor extends TextCellEditor { - - public TextValueCellEditor(Composite parent) { - super(parent); - } - - @Override - protected void doSetValue(Object value) { - if (value instanceof UiAttributeNode) { - super.doSetValue(((UiAttributeNode)value).getCurrentValue()); - return; - } - - super.doSetValue(value); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/UiElementPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/UiElementPart.java deleted file mode 100644 index 66773bd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/UiElementPart.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.ManifestEditor; -import com.android.ide.eclipse.editors.ui.SectionHelper.ManifestSectionPart; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; - -/** - * Generic page's section part that displays all attributes of a given {@link UiElementNode}. - * <p/> - * This part is designed to be displayed in a page that has a table column layout. - * It is linked to a specific {@link UiElementNode} and automatically displays all of its - * attributes, manages its dirty state and commits the attributes when necessary. - * <p/> - * No derivation is needed unless the UI or workflow needs to be extended. - */ -public class UiElementPart extends ManifestSectionPart { - - /** A reference to the container editor */ - private ManifestEditor mEditor; - /** The {@link UiElementNode} manipulated by this SectionPart. It can be null. */ - private UiElementNode mUiElementNode; - /** Table that contains all the attributes */ - private Composite mTable; - - public UiElementPart(Composite body, FormToolkit toolkit, ManifestEditor editor, - UiElementNode uiElementNode, String sectionTitle, String sectionDescription, - int extra_style) { - super(body, toolkit, extra_style, sectionDescription != null); - mEditor = editor; - mUiElementNode = uiElementNode; - setupSection(sectionTitle, sectionDescription); - - if (uiElementNode == null) { - // This is serious and should never happen. Instead of crashing, simply abort. - // There will be no UI, which will prevent further damage. - AdtPlugin.log(IStatus.ERROR, "Missing node to edit!"); //$NON-NLS-1$ - return; - } - } - - /** - * Returns the Editor associated with this part. - */ - public ManifestEditor getEditor() { - return mEditor; - } - - /** - * Returns the {@link UiElementNode} associated with this part. - */ - public UiElementNode getUiElementNode() { - return mUiElementNode; - } - - /** - * Changes the element node handled by this part. - * - * @param uiElementNode The new element node for the part. - */ - public void setUiElementNode(UiElementNode uiElementNode) { - mUiElementNode = uiElementNode; - } - - /** - * Initializes the form part. - * <p/> - * This is called by the owning managed form as soon as the part is added to the form, - * which happens right after the part is actually created. - */ - @Override - public void initialize(IManagedForm form) { - super.initialize(form); - createFormControls(form); - } - - /** - * Setup the section that contains this part. - * <p/> - * This is called by the constructor to set the section's title and description - * with parameters given in the constructor. - * <br/> - * Derived class override this if needed, however in most cases the default - * implementation should be enough. - * - * @param sectionTitle The section part's title - * @param sectionDescription The section part's description - */ - protected void setupSection(String sectionTitle, String sectionDescription) { - Section section = getSection(); - section.setText(sectionTitle); - section.setDescription(sectionDescription); - } - - /** - * Create the controls to edit the attributes for the given ElementDescriptor. - * <p/> - * This MUST not be called by the constructor. Instead it must be called from - * <code>initialize</code> (i.e. right after the form part is added to the managed form.) - * <p/> - * Derived classes can override this if necessary. - * - * @param managedForm The owner managed form - */ - protected void createFormControls(IManagedForm managedForm) { - setTable(createTableLayout(managedForm.getToolkit(), 2 /* numColumns */)); - - createUiAttributes(managedForm); - } - - /** - * Sets the table where the attribute UI needs to be created. - */ - protected void setTable(Composite table) { - mTable = table; - } - - /** - * Returns the table where the attribute UI needs to be created. - */ - protected Composite getTable() { - return mTable; - } - - /** - * Add all the attribute UI widgets into the underlying table layout. - * - * @param managedForm The owner managed form - */ - protected void createUiAttributes(IManagedForm managedForm) { - Composite table = getTable(); - if (table == null || managedForm == null) { - return; - } - - // Remove any old UI controls - for (Control c : table.getChildren()) { - c.dispose(); - } - - fillTable(table, managedForm); - - // Tell the section that the layout has changed. - layoutChanged(); - } - - /** - * Actually fills the table. - * This is called by {@link #createUiAttributes(IManagedForm)} to populate the new - * table. The default implementation is to use - * {@link #insertUiAttributes(UiElementNode, Composite, IManagedForm)} to actually - * place the attributes of the default {@link UiElementNode} in the table. - * <p/> - * Derived classes can override this to add controls in the table before or after. - * - * @param table The table to fill. It must have 2 columns. - * @param managedForm The managed form for new controls. - */ - protected void fillTable(Composite table, IManagedForm managedForm) { - int inserted = insertUiAttributes(mUiElementNode, table, managedForm); - - if (inserted == 0) { - createLabel(table, managedForm.getToolkit(), - "No attributes to display, waiting for SDK to finish loading...", - null /* tooltip */ ); - } - } - - /** - * Insert the UI attributes of the given {@link UiElementNode} in the given table. - * - * @param uiNode The {@link UiElementNode} that contains the attributes to display. - * Must not be null. - * @param table The table to fill. It must have 2 columns. - * @param managedForm The managed form for new controls. - * @return The number of UI attributes inserted. It is >= 0. - */ - protected int insertUiAttributes(UiElementNode uiNode, Composite table, IManagedForm managedForm) { - if (uiNode == null || table == null || managedForm == null) { - return 0; - } - - // To iterate over all attributes, we use the {@link ElementDescriptor} instead - // of the {@link UiElementNode} because the attributes' order is guaranteed in the - // descriptor but not in the node itself. - AttributeDescriptor[] attr_desc_list = uiNode.getAttributeDescriptors(); - for (AttributeDescriptor attr_desc : attr_desc_list) { - if (attr_desc instanceof XmlnsAttributeDescriptor) { - // Do not show hidden attributes - continue; - } - - UiAttributeNode ui_attr = uiNode.findUiAttribute(attr_desc); - if (ui_attr != null) { - ui_attr.createUiControl(table, managedForm); - } else { - // The XML has an extra attribute which wasn't declared in - // AndroidManifestDescriptors. This is not a problem, we just ignore it. - AdtPlugin.log(IStatus.WARNING, - "Attribute %1$s not declared in node %2$s, ignored.", //$NON-NLS-1$ - attr_desc.getXmlLocalName(), - uiNode.getDescriptor().getXmlName()); - } - } - return attr_desc_list.length; - } - - /** - * Tests whether the part is dirty i.e. its widgets have state that is - * newer than the data in the model. - * <p/> - * This is done by iterating over all attributes and updating the super's - * internal dirty flag. Stop once at least one attribute is dirty. - * - * @return <code>true</code> if the part is dirty, <code>false</code> - * otherwise. - */ - @Override - public boolean isDirty() { - if (mUiElementNode != null && !super.isDirty()) { - for (UiAttributeNode ui_attr : mUiElementNode.getUiAttributes()) { - if (ui_attr.isDirty()) { - markDirty(); - break; - } - } - } - return super.isDirty(); - } - - /** - * If part is displaying information loaded from a model, this method - * instructs it to commit the new (modified) data back into the model. - * - * @param onSave - * indicates if commit is called during 'save' operation or for - * some other reason (for example, if form is contained in a - * wizard or a multi-page editor and the user is about to leave - * the page). - */ - @Override - public void commit(boolean onSave) { - if (mUiElementNode != null) { - mEditor.editXmlModel(new Runnable() { - public void run() { - for (UiAttributeNode ui_attr : mUiElementNode.getUiAttributes()) { - ui_attr.commit(); - } - } - }); - } - - // We need to call super's commit after we synchronized the nodes to make sure we - // reset the dirty flag after all the side effects from committing have occurred. - super.commit(onSave); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/CopyCutAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/CopyCutAction.java deleted file mode 100644 index 2aad217..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/CopyCutAction.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui.tree; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.apache.xml.serialize.Method; -import org.apache.xml.serialize.OutputFormat; -import org.apache.xml.serialize.XMLSerializer; -import org.eclipse.jface.action.Action; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; -import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; -import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; -import org.eclipse.wst.xml.core.internal.document.NodeContainer; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - - -/** - * Provides Cut and Copy actions for the tree nodes. - */ -public class CopyCutAction extends Action { - private List<UiElementNode> mUiNodes; - private boolean mPerformCut; - private final AndroidEditor mEditor; - private final Clipboard mClipboard; - private final ICommitXml mXmlCommit; - - /** - * Creates a new Copy or Cut action. - * - * @param selected The UI node to cut or copy. It *must* have a non-null XML node. - * @param perform_cut True if the operation is cut, false if it is copy. - */ - public CopyCutAction(AndroidEditor editor, Clipboard clipboard, ICommitXml xmlCommit, - UiElementNode selected, boolean perform_cut) { - this(editor, clipboard, xmlCommit, toList(selected), perform_cut); - } - - /** - * Creates a new Copy or Cut action. - * - * @param selected The UI nodes to cut or copy. They *must* have a non-null XML node. - * The list becomes owned by the {@link CopyCutAction}. - * @param perform_cut True if the operation is cut, false if it is copy. - */ - public CopyCutAction(AndroidEditor editor, Clipboard clipboard, ICommitXml xmlCommit, - List<UiElementNode> selected, boolean perform_cut) { - super(perform_cut ? "Cut" : "Copy"); - mEditor = editor; - mClipboard = clipboard; - mXmlCommit = xmlCommit; - - ISharedImages images = PlatformUI.getWorkbench().getSharedImages(); - if (perform_cut) { - setImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_CUT)); - setHoverImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_CUT)); - setDisabledImageDescriptor( - images.getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED)); - } else { - setImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_COPY)); - setHoverImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_COPY)); - setDisabledImageDescriptor( - images.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED)); - } - - mUiNodes = selected; - mPerformCut = perform_cut; - } - - /** - * Performs the cut or copy action. - * First an XML serializer is used to turn the existing XML node into a valid - * XML fragment, which is added as text to the clipboard. - */ - @Override - public void run() { - super.run(); - if (mUiNodes == null || mUiNodes.size() < 1) { - return; - } - - // Commit the current pages first, to make sure the XML is in sync. - // Committing may change the XML structure. - if (mXmlCommit != null) { - mXmlCommit.commitPendingXmlChanges(); - } - - StringBuilder allText = new StringBuilder(); - ArrayList<UiElementNode> nodesToCut = mPerformCut ? new ArrayList<UiElementNode>() : null; - - for (UiElementNode uiNode : mUiNodes) { - try { - Node xml_node = uiNode.getXmlNode(); - if (xml_node == null) { - return; - } - - String data = getXmlTextFromEditor(xml_node); - - // In the unlikely event that IStructuredDocument failed to extract the text - // directly from the editor, try to fall back on a direct XML serialization - // of the XML node. This uses the generic Node interface with no SSE tricks. - if (data == null) { - data = getXmlTextFromSerialization(xml_node); - } - - if (data != null) { - allText.append(data); - if (mPerformCut) { - // only remove notes to cut if we actually got some XML text from them - nodesToCut.add(uiNode); - } - } - - } catch (Exception e) { - AdtPlugin.log(e, "CopyCutAction failed for UI node %1$s", //$NON-NLS-1$ - uiNode.getBreadcrumbTrailDescription(true)); - } - } // for uiNode - - if (allText != null && allText.length() > 0) { - mClipboard.setContents( - new Object[] { allText.toString() }, - new Transfer[] { TextTransfer.getInstance() }); - if (mPerformCut) { - for (UiElementNode uiNode : nodesToCut) { - uiNode.deleteXmlNode(); - } - } - } - } - - /** Get the data directly from the editor. */ - private String getXmlTextFromEditor(Node xml_node) { - String data = null; - IStructuredModel model = mEditor.getModelForRead(); - try { - IStructuredDocument sse_doc = mEditor.getStructuredDocument(); - if (xml_node instanceof NodeContainer) { - // The easy way to get the source of an SSE XML node. - data = ((NodeContainer) xml_node).getSource(); - } else if (xml_node instanceof IndexedRegion && sse_doc != null) { - // Try harder. - IndexedRegion region = (IndexedRegion) xml_node; - int start = region.getStartOffset(); - int end = region.getEndOffset(); - - if (end > start) { - data = sse_doc.get(start, end - start); - } - } - } catch (BadLocationException e) { - // the region offset was invalid. ignore. - } finally { - model.releaseFromRead(); - } - return data; - } - - /** - * Direct XML serialization of the XML node. - * <p/> - * This uses the generic Node interface with no SSE tricks. It's however slower - * and doesn't respect formatting (since serialization is involved instead of reading - * the actual text buffer.) - */ - private String getXmlTextFromSerialization(Node xml_node) throws IOException { - String data; - StringWriter sw = new StringWriter(); - XMLSerializer serializer = new XMLSerializer(sw, - new OutputFormat(Method.XML, - OutputFormat.Defaults.Encoding /* utf-8 */, - true /* indent */)); - // Serialize will throw an IOException if it fails. - serializer.serialize((Element) xml_node); - data = sw.toString(); - return data; - } - - /** - * Static helper class to wrap on node into a list for the constructors. - */ - private static ArrayList<UiElementNode> toList(UiElementNode selected) { - ArrayList<UiElementNode> list = null; - if (selected != null) { - list = new ArrayList<UiElementNode>(1); - list.add(selected); - } - return list; - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/ICommitXml.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/ICommitXml.java deleted file mode 100644 index 8b6aa0e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/ICommitXml.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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.editors.ui.tree; - -/** - * Interface for an object that can commit its changes to the underlying XML model - */ -public interface ICommitXml { - - /** Commits pending data to the underlying XML model. */ - public void commitPendingXmlChanges(); - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java deleted file mode 100644 index 0729881..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui.tree; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog; -import org.eclipse.ui.dialogs.ISelectionStatusValidator; - -import java.util.Arrays; - -/** - * A selection dialog to select the type of the new element node to - * created, either in the application node or the selected sub node. - */ -public class NewItemSelectionDialog extends AbstractElementListSelectionDialog { - - /** The UI node selected in the tree view before creating the new item selection dialog. - * Can be null -- which means new items must be created in the root_node. */ - private UiElementNode mSelectedUiNode; - /** The root node chosen by the user, either root_node or the one passed - * to the constructor if not null */ - private UiElementNode mChosenRootNode; - private UiElementNode mLocalRootNode; - /** The descriptor of the elements to be displayed as root in this tree view. All elements - * of the same type in the root will be displayed. */ - private ElementDescriptor[] mDescriptorFilters; - - /** - * Creates the new item selection dialog. - * - * @param shell The parent shell for the list. - * @param labelProvider ILabelProvider for the list. - * @param descriptorFilters The element allows at the root of the tree - * @param ui_node The selected node, or null if none is selected. - * @param root_node The root of the Ui Tree, either the UiDocumentNode or a sub-node. - */ - public NewItemSelectionDialog(Shell shell, ILabelProvider labelProvider, - ElementDescriptor[] descriptorFilters, - UiElementNode ui_node, - UiElementNode root_node) { - super(shell, labelProvider); - mDescriptorFilters = descriptorFilters; - mLocalRootNode = root_node; - - // Only accept the UI node if it is not the UI root node and it can have children. - // If the node cannot have children, select its parent as a potential target. - if (ui_node != null && ui_node != mLocalRootNode) { - if (ui_node.getDescriptor().hasChildren()) { - mSelectedUiNode = ui_node; - } else { - UiElementNode parent = ui_node.getUiParent(); - if (parent != null && parent != mLocalRootNode) { - mSelectedUiNode = parent; - } - } - } - - setHelpAvailable(false); - setMultipleSelection(false); - - setValidator(new ISelectionStatusValidator() { - public IStatus validate(Object[] selection) { - if (selection.length == 1 && selection[0] instanceof ViewElementDescriptor) { - return new Status(IStatus.OK, // severity - AdtPlugin.PLUGIN_ID, //plugin id - IStatus.OK, // code - ((ViewElementDescriptor) selection[0]).getCanonicalClassName(), //msg - null); // exception - } else if (selection.length == 1 && selection[0] instanceof ElementDescriptor) { - return new Status(IStatus.OK, // severity - AdtPlugin.PLUGIN_ID, //plugin id - IStatus.OK, // code - "", //$NON-NLS-1$ // msg - null); // exception - } else { - return new Status(IStatus.ERROR, // severity - AdtPlugin.PLUGIN_ID, //plugin id - IStatus.ERROR, // code - "Invalid selection", // msg, translatable - null); // exception - } - } - }); - } - - /** - * @return The root node selected by the user, either root node or the - * one passed to the constructor if not null. - */ - public UiElementNode getChosenRootNode() { - return mChosenRootNode; - } - - /** - * Internal helper to compute the result. Returns the selection from - * the list view, if any. - */ - @Override - protected void computeResult() { - setResult(Arrays.asList(getSelectedElements())); - } - - /** - * Creates the dialog area. - * - * First add a radio area, which may be either 2 radio controls or - * just a message area if there's only one choice (the app root node). - * - * Then uses the default from the AbstractElementListSelectionDialog - * which is to add both a filter text and a filtered list. Adding both - * is necessary (since the base class accesses both internal directly - * fields without checking for null pointers.) - * - * Finally sets the initial selection list. - */ - @Override - protected Control createDialogArea(Composite parent) { - Composite contents = (Composite) super.createDialogArea(parent); - - createRadioControl(contents); - createFilterText(contents); - createFilteredList(contents); - - // Initialize the list state. - // This must be done after the filtered list as been created. - chooseNode(mChosenRootNode); - setSelection(getInitialElementSelections().toArray()); - return contents; - } - - /** - * Creates the message text widget and sets layout data. - * @param content the parent composite of the message area. - */ - private Composite createRadioControl(Composite content) { - - if (mSelectedUiNode != null) { - Button radio1 = new Button(content, SWT.RADIO); - radio1.setText(String.format("Create a new element at the top level, in %1$s.", - mLocalRootNode.getShortDescription())); - - Button radio2 = new Button(content, SWT.RADIO); - radio2.setText(String.format("Create a new element in the selected element, %1$s.", - mSelectedUiNode.getBreadcrumbTrailDescription(false /* include_root */))); - - // Set the initial selection before adding the listeners - // (they can't be run till the filtered list has been created) - radio1.setSelection(false); - radio2.setSelection(true); - mChosenRootNode = mSelectedUiNode; - - radio1.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - chooseNode(mLocalRootNode); - } - }); - - radio2.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - chooseNode(mSelectedUiNode); - } - }); - } else { - setMessage(String.format("Create a new element at the top level, in %1$s.", - mLocalRootNode.getShortDescription())); - createMessageArea(content); - - mChosenRootNode = mLocalRootNode; - } - - return content; - } - - /** - * Internal helper to remember the root node choosen by the user. - * It also sets the list view to the adequate list of children that can - * be added to the chosen root node. - * - * If the chosen root node is mLocalRootNode and a descriptor filter was specified - * when creating the master-detail part, we use this as the set of nodes that - * can be created on the root node. - * - * @param ui_node The chosen root node, either mLocalRootNode or - * mSelectedUiNode. - */ - private void chooseNode(UiElementNode ui_node) { - mChosenRootNode = ui_node; - - if (ui_node == mLocalRootNode && - mDescriptorFilters != null && - mDescriptorFilters.length != 0) { - setListElements(mDescriptorFilters); - } else { - setListElements(ui_node.getDescriptor().getChildren()); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/PasteAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/PasteAction.java deleted file mode 100644 index 8bb4ad2..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/PasteAction.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.ui.tree; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; -import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; -import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; -import org.eclipse.wst.xml.core.internal.document.NodeContainer; -import org.w3c.dom.Node; - - -/** - * Provides Paste operation for the tree nodes - */ -public class PasteAction extends Action { - private UiElementNode mUiNode; - private final AndroidEditor mEditor; - private final Clipboard mClipboard; - - public PasteAction(AndroidEditor editor, Clipboard clipboard, UiElementNode ui_node) { - super("Paste"); - mEditor = editor; - mClipboard = clipboard; - - ISharedImages images = PlatformUI.getWorkbench().getSharedImages(); - setImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE)); - setHoverImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE)); - setDisabledImageDescriptor( - images.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED)); - - mUiNode = ui_node; - } - - /** - * Performs the paste operation. - */ - @Override - public void run() { - super.run(); - - final String data = (String) mClipboard.getContents(TextTransfer.getInstance()); - if (data != null) { - IStructuredModel model = mEditor.getModelForEdit(); - try { - IStructuredDocument sse_doc = mEditor.getStructuredDocument(); - if (sse_doc != null) { - if (mUiNode.getDescriptor().hasChildren()) { - // This UI Node can have children. The new XML is - // inserted as the first child. - - if (mUiNode.getUiChildren().size() > 0) { - // There's already at least one child, so insert right before it. - Node xml_node = mUiNode.getUiChildren().get(0).getXmlNode(); - if (xml_node instanceof IndexedRegion) { // implies xml_node != null - IndexedRegion region = (IndexedRegion) xml_node; - sse_doc.replace(region.getStartOffset(), 0, data); - return; // we're done, no need to try the other cases - } - } - - // If there's no first XML node child. Create one by - // inserting at the end of the *start* tag. - Node xml_node = mUiNode.getXmlNode(); - if (xml_node instanceof NodeContainer) { - NodeContainer container = (NodeContainer) xml_node; - IStructuredDocumentRegion start_tag = - container.getStartStructuredDocumentRegion(); - if (start_tag != null) { - sse_doc.replace(start_tag.getEndOffset(), 0, data); - return; // we're done, no need to try the other case - } - } - } - - // This UI Node doesn't accept children. The new XML is inserted as the - // next sibling. This also serves as a fallback if all the previous - // attempts failed. However, this is not possible if the current node - // has for parent a document -- an XML document can only have one root, - // with no siblings. - if (!(mUiNode.getUiParent() instanceof UiDocumentNode)) { - Node xml_node = mUiNode.getXmlNode(); - if (xml_node instanceof IndexedRegion) { - IndexedRegion region = (IndexedRegion) xml_node; - sse_doc.replace(region.getEndOffset(), 0, data); - } - } - } - - } catch (BadLocationException e) { - AdtPlugin.log(e, "ParseAction failed for UI Node %2$s, content '%1$s'", //$NON-NLS-1$ - mUiNode.getBreadcrumbTrailDescription(true), data); - } finally { - model.releaseFromEdit(); - } - } - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiActions.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiActions.java deleted file mode 100644 index 21180b1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiActions.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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.editors.ui.tree; - -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.swt.widgets.Shell; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -import java.util.List; - -/** - * Performs basic actions on an XML tree: add node, remove node, move up/down. - */ -public abstract class UiActions implements ICommitXml { - - public UiActions() { - } - - //--------------------- - // Actual implementations must override these to provide specific hooks - - /** Returns the UiDocumentNode for the current model. */ - abstract protected UiElementNode getRootNode(); - - /** Commits pending data before the XML model is modified. */ - abstract public void commitPendingXmlChanges(); - - /** - * Utility method to select an outline item based on its model node - * - * @param uiNode The node to select. Can be null (in which case nothing should happen) - */ - abstract protected void selectUiNode(UiElementNode uiNode); - - //--------------------- - - /** - * Called when the "Add..." button next to the tree view is selected. - * <p/> - * This simplified version of doAdd does not support descriptor filters and creates - * a new {@link UiModelTreeLabelProvider} for each call. - */ - public void doAdd(UiElementNode uiNode, Shell shell) { - doAdd(uiNode, null /* descriptorFilters */, shell, new UiModelTreeLabelProvider()); - } - - /** - * Called when the "Add..." button next to the tree view is selected. - * - * Displays a selection dialog that lets the user select which kind of node - * to create, depending on the current selection. - */ - public void doAdd(UiElementNode uiNode, - ElementDescriptor[] descriptorFilters, - Shell shell, ILabelProvider labelProvider) { - // If the root node is a document with already a root, use it as the root node - UiElementNode rootNode = getRootNode(); - if (rootNode instanceof UiDocumentNode && rootNode.getUiChildren().size() > 0) { - rootNode = rootNode.getUiChildren().get(0); - } - - NewItemSelectionDialog dlg = new NewItemSelectionDialog( - shell, - labelProvider, - descriptorFilters, - uiNode, rootNode); - dlg.open(); - Object[] results = dlg.getResult(); - if (results != null && results.length > 0) { - addElement(dlg.getChosenRootNode(), null, (ElementDescriptor) results[0], - true /*updateLayout*/); - } - } - - /** - * Adds a new XML element based on the {@link ElementDescriptor} to the given parent - * {@link UiElementNode}, and then select it. - * <p/> - * If the parent is a document root which already contains a root element, the inner - * root element is used as the actual parent. This ensure you can't create a broken - * XML file with more than one root element. - * <p/> - * If a sibling is given and that sibling has the same parent, the new node is added - * right after that sibling. Otherwise the new node is added at the end of the parent - * child list. - * - * @param uiParent An existing UI node or null to add to the tree root - * @param uiSibling An existing UI node before which to insert the new node. Can be null. - * @param descriptor The descriptor of the element to add - * @param updateLayout True if layout attributes should be set - * @return The new {@link UiElementNode} or null. - */ - public UiElementNode addElement(UiElementNode uiParent, - UiElementNode uiSibling, - ElementDescriptor descriptor, - boolean updateLayout) { - if (uiParent instanceof UiDocumentNode && uiParent.getUiChildren().size() > 0) { - uiParent = uiParent.getUiChildren().get(0); - } - if (uiSibling != null && uiSibling.getUiParent() != uiParent) { - uiSibling = null; - } - - UiElementNode uiNew = addNewTreeElement(uiParent, uiSibling, descriptor, updateLayout); - selectUiNode(uiNew); - - return uiNew; - } - - /** - * Called when the "Remove" button is selected. - * - * If the tree has a selection, remove it. - * This simply deletes the XML node attached to the UI node: when the XML model fires the - * update event, the tree will get refreshed. - */ - public void doRemove(final List<UiElementNode> nodes, Shell shell) { - - if (nodes == null || nodes.size() == 0) { - return; - } - - final int len = nodes.size(); - - StringBuilder sb = new StringBuilder(); - for (UiElementNode node : nodes) { - sb.append("\n- "); //$NON-NLS-1$ - sb.append(node.getBreadcrumbTrailDescription(false /* include_root */)); - } - - if (MessageDialog.openQuestion(shell, - len > 1 ? "Remove elements from Android XML" // title - : "Remove element from Android XML", - String.format("Do you really want to remove %1$s?", sb.toString()))) { - commitPendingXmlChanges(); - getRootNode().getEditor().editXmlModel(new Runnable() { - public void run() { - UiElementNode previous = null; - UiElementNode parent = null; - - for (int i = len - 1; i >= 0; i--) { - UiElementNode node = nodes.get(i); - previous = node.getUiPreviousSibling(); - parent = node.getUiParent(); - - // delete node - node.deleteXmlNode(); - } - - // try to select the last previous sibling or the last parent - if (previous != null) { - selectUiNode(previous); - } else if (parent != null) { - selectUiNode(parent); - } - } - }); - } - } - - /** - * Called when the "Up" button is selected. - * <p/> - * If the tree has a selection, move it up, either in the child list or as the last child - * of the previous parent. - */ - public void doUp(final List<UiElementNode> nodes) { - if (nodes == null || nodes.size() < 1) { - return; - } - - final Node[] select_xml_node = { null }; - UiElementNode last_node = null; - UiElementNode search_root = null; - - for (int i = 0; i < nodes.size(); i++) { - final UiElementNode node = last_node = nodes.get(i); - - // the node will move either up to its parent or grand-parent - search_root = node.getUiParent(); - if (search_root != null && search_root.getUiParent() != null) { - search_root = search_root.getUiParent(); - } - - commitPendingXmlChanges(); - getRootNode().getEditor().editXmlModel(new Runnable() { - public void run() { - Node xml_node = node.getXmlNode(); - if (xml_node != null) { - Node xml_parent = xml_node.getParentNode(); - if (xml_parent != null) { - UiElementNode ui_prev = node.getUiPreviousSibling(); - if (ui_prev != null && ui_prev.getXmlNode() != null) { - // This node is not the first one of the parent, so it can be - // removed and then inserted before its previous sibling. - // If the previous sibling can have children, though, then it - // is inserted at the end of the children list. - Node xml_prev = ui_prev.getXmlNode(); - if (ui_prev.getDescriptor().hasChildren()) { - xml_prev.appendChild(xml_parent.removeChild(xml_node)); - select_xml_node[0] = xml_node; - } else { - xml_parent.insertBefore( - xml_parent.removeChild(xml_node), - xml_prev); - select_xml_node[0] = xml_node; - } - } else if (!(xml_parent instanceof Document) && - xml_parent.getParentNode() != null && - !(xml_parent.getParentNode() instanceof Document)) { - // If the node is the first one of the child list of its - // parent, move it up in the hierarchy as previous sibling - // to the parent. This is only possible if the parent of the - // parent is not a document. - Node grand_parent = xml_parent.getParentNode(); - grand_parent.insertBefore(xml_parent.removeChild(xml_node), - xml_parent); - select_xml_node[0] = xml_node; - } - } - } - } - }); - } - - if (select_xml_node[0] == null) { - // The XML node has not been moved, we can just select the same UI node - selectUiNode(last_node); - } else { - // The XML node has moved. At this point the UI model has been reloaded - // and the XML node has been affected to a new UI node. Find that new UI - // node and select it. - if (search_root == null) { - search_root = last_node.getUiRoot(); - } - if (search_root != null) { - selectUiNode(search_root.findXmlNode(select_xml_node[0])); - } - } - } - - /** - * Called when the "Down" button is selected. - * - * If the tree has a selection, move it down, either in the same child list or as the - * first child of the next parent. - */ - public void doDown(final List<UiElementNode> nodes) { - if (nodes == null || nodes.size() < 1) { - return; - } - - final Node[] select_xml_node = { null }; - UiElementNode last_node = null; - UiElementNode search_root = null; - - for (int i = nodes.size() - 1; i >= 0; i--) { - final UiElementNode node = last_node = nodes.get(i); - // the node will move either down to its parent or grand-parent - search_root = node.getUiParent(); - if (search_root != null && search_root.getUiParent() != null) { - search_root = search_root.getUiParent(); - } - - commitPendingXmlChanges(); - getRootNode().getEditor().editXmlModel(new Runnable() { - public void run() { - Node xml_node = node.getXmlNode(); - if (xml_node != null) { - Node xml_parent = xml_node.getParentNode(); - if (xml_parent != null) { - UiElementNode uiNext = node.getUiNextSibling(); - if (uiNext != null && uiNext.getXmlNode() != null) { - // This node is not the last one of the parent, so it can be - // removed and then inserted after its next sibling. - // If the next sibling is a node that can have children, though, - // then the node is inserted as the first child. - Node xml_next = uiNext.getXmlNode(); - if (uiNext.getDescriptor().hasChildren()) { - // Note: insertBefore works as append if the ref node is - // null, i.e. when the node doesn't have children yet. - xml_next.insertBefore(xml_parent.removeChild(xml_node), - xml_next.getFirstChild()); - select_xml_node[0] = xml_node; - } else { - // Insert "before after next" ;-) - xml_parent.insertBefore(xml_parent.removeChild(xml_node), - xml_next.getNextSibling()); - select_xml_node[0] = xml_node; - } - } else if (!(xml_parent instanceof Document) && - xml_parent.getParentNode() != null && - !(xml_parent.getParentNode() instanceof Document)) { - // This node is the last node of its parent. - // If neither the parent nor the grandparent is a document, - // then the node can be insert right after the parent. - Node grand_parent = xml_parent.getParentNode(); - grand_parent.insertBefore(xml_parent.removeChild(xml_node), - xml_parent.getNextSibling()); - select_xml_node[0] = xml_node; - } - } - } - } - }); - } - - if (select_xml_node[0] == null) { - // The XML node has not been moved, we can just select the same UI node - selectUiNode(last_node); - } else { - // The XML node has moved. At this point the UI model has been reloaded - // and the XML node has been affected to a new UI node. Find that new UI - // node and select it. - if (search_root == null) { - search_root = last_node.getUiRoot(); - } - if (search_root != null) { - selectUiNode(search_root.findXmlNode(select_xml_node[0])); - } - } - } - - //--------------------- - - /** - * Adds a new element of the given descriptor's type to the given UI parent node. - * - * This actually creates the corresponding XML node in the XML model, which in turn - * will refresh the current tree view. - * - * @param uiParent An existing UI node or null to add to the tree root - * @param uiSibling An existing UI node to insert right before. Can be null. - * @param descriptor The descriptor of the element to add - * @param updateLayout True if layout attributes should be set - * @return The {@link UiElementNode} that has been added to the UI tree. - */ - private UiElementNode addNewTreeElement(UiElementNode uiParent, - final UiElementNode uiSibling, - ElementDescriptor descriptor, - final boolean updateLayout) { - commitPendingXmlChanges(); - - int index = 0; - for (UiElementNode uiChild : uiParent.getUiChildren()) { - if (uiChild == uiSibling) { - break; - } - index++; - } - - final UiElementNode uiNew = uiParent.insertNewUiChild(index, descriptor); - UiElementNode rootNode = getRootNode(); - - rootNode.getEditor().editXmlModel(new Runnable() { - public void run() { - DescriptorsUtils.setDefaultLayoutAttributes(uiNew, updateLayout); - Node xmlNode = uiNew.createXmlNode(); - } - }); - return uiNew; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiElementDetail.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiElementDetail.java deleted file mode 100644 index 15c67c3..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiElementDetail.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui.tree; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.ide.eclipse.editors.ui.SectionHelper.ManifestSectionPart; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ITreeSelection; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.ui.forms.IDetailsPage; -import org.eclipse.ui.forms.IFormPart; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.events.ExpansionEvent; -import org.eclipse.ui.forms.events.IExpansionListener; -import org.eclipse.ui.forms.widgets.FormText; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; -import org.eclipse.ui.forms.widgets.SharedScrolledComposite; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.eclipse.ui.forms.widgets.TableWrapLayout; -import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; - -import java.util.Collection; -import java.util.HashSet; - -/** - * Details page for the {@link UiElementNode} nodes in the tree view. - * <p/> - * See IDetailsBase for more details. - */ -class UiElementDetail implements IDetailsPage { - - /** The master-detail part, composed of a main tree and an auxiliary detail part */ - private ManifestSectionPart mMasterPart; - - private Section mMasterSection; - private UiElementNode mCurrentUiElementNode; - private Composite mCurrentTable; - private boolean mIsDirty; - - private IManagedForm mManagedForm; - - private final UiTreeBlock mTree; - - public UiElementDetail(UiTreeBlock tree) { - mTree = tree; - mMasterPart = mTree.getMasterPart(); - mManagedForm = mMasterPart.getManagedForm(); - } - - /* (non-java doc) - * Initializes the part. - */ - public void initialize(IManagedForm form) { - mManagedForm = form; - } - - /* (non-java doc) - * Creates the contents of the page in the provided parent. - */ - public void createContents(Composite parent) { - mMasterSection = createMasterSection(parent); - } - - /* (non-java doc) - * Called when the provided part has changed selection state. - * <p/> - * Only reply when our master part originates the selection. - */ - public void selectionChanged(IFormPart part, ISelection selection) { - if (part == mMasterPart && - !selection.isEmpty() && - selection instanceof ITreeSelection) { - ITreeSelection tree_selection = (ITreeSelection) selection; - - Object first = tree_selection.getFirstElement(); - if (first instanceof UiElementNode) { - UiElementNode ui_node = (UiElementNode) first; - createUiAttributeControls(mManagedForm, ui_node); - } - } - } - - /* (non-java doc) - * Instructs it to commit the new (modified) data back into the model. - */ - public void commit(boolean onSave) { - - IStructuredModel model = mTree.getEditor().getModelForEdit(); - try { - // Notify the model we're about to change data... - model.aboutToChangeModel(); - - if (mCurrentUiElementNode != null) { - mCurrentUiElementNode.commit(); - } - - // Finally reset the dirty flag if everything was saved properly - mIsDirty = false; - } catch (Exception e) { - AdtPlugin.log(e, "Detail node failed to commit XML attribute!"); //$NON-NLS-1$ - } finally { - // Notify the model we're done modifying it. This must *always* be executed. - model.changedModel(); - model.releaseFromEdit(); - } - } - - public void dispose() { - // pass - } - - - /* (non-java doc) - * Returns true if the part has been modified with respect to the data - * loaded from the model. - */ - public boolean isDirty() { - if (mCurrentUiElementNode != null && mCurrentUiElementNode.isDirty()) { - markDirty(); - } - return mIsDirty; - } - - public boolean isStale() { - // pass - return false; - } - - /** - * Called by the master part when the tree is refreshed after the framework resources - * have been reloaded. - */ - public void refresh() { - if (mCurrentTable != null) { - mCurrentTable.dispose(); - mCurrentTable = null; - } - mCurrentUiElementNode = null; - mMasterSection.getParent().pack(true /* changed */); - } - - public void setFocus() { - // pass - } - - public boolean setFormInput(Object input) { - // pass - return false; - } - - /** - * Creates a TableWrapLayout in the DetailsPage, which in turns contains a Section. - * - * All the UI should be created in a layout which parent is the mSection itself. - * The hierarchy is: - * <pre> - * DetailPage - * + TableWrapLayout - * + Section (with title/description && fill_grab horizontal) - * + TableWrapLayout [*] - * + Labels/Forms/etc... [*] - * </pre> - * Both items marked with [*] are created by the derived classes to fit their needs. - * - * @param parent Parent of the mSection (from createContents) - * @return The new Section - */ - private Section createMasterSection(Composite parent) { - TableWrapLayout layout = new TableWrapLayout(); - layout.topMargin = 0; - parent.setLayout(layout); - - FormToolkit toolkit = mManagedForm.getToolkit(); - Section section = toolkit.createSection(parent, Section.TITLE_BAR); - section.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.TOP)); - return section; - } - - /** - * Create the ui attribute controls to edit the attributes for the given - * ElementDescriptor. - * <p/> - * This is called by the constructor. - * Derived classes can override this if necessary. - * - * @param managedForm The managed form - */ - private void createUiAttributeControls( - final IManagedForm managedForm, - final UiElementNode ui_node) { - - final ElementDescriptor elem_desc = ui_node.getDescriptor(); - mMasterSection.setText(String.format("Attributes for %1$s", ui_node.getShortDescription())); - - if (mCurrentUiElementNode != ui_node) { - // Before changing the table, commit all dirty state. - if (mIsDirty) { - commit(false); - } - if (mCurrentTable != null) { - mCurrentTable.dispose(); - mCurrentTable = null; - } - - // To iterate over all attributes, we use the {@link ElementDescriptor} instead - // of the {@link UiElementNode} because the attributes order is guaranteed in the - // descriptor but not in the node itself. - AttributeDescriptor[] attr_desc_list = ui_node.getAttributeDescriptors(); - - // If the attribute list contains at least one SeparatorAttributeDescriptor, - // sub-sections will be used. This needs to be known early as it influences the - // creation of the master table. - boolean useSubsections = false; - for (AttributeDescriptor attr_desc : attr_desc_list) { - if (attr_desc instanceof SeparatorAttributeDescriptor) { - // Sub-sections will be used. The default sections should no longer be - useSubsections = true; - break; - } - } - - FormToolkit toolkit = managedForm.getToolkit(); - Composite masterTable = SectionHelper.createTableLayout(mMasterSection, - toolkit, useSubsections ? 1 : 2 /* numColumns */); - mCurrentTable = masterTable; - - mCurrentUiElementNode = ui_node; - - if (elem_desc.getTooltip() != null) { - String tooltip; - if (Sdk.getCurrent() != null && - Sdk.getCurrent().getDocumentationBaseUrl() != null) { - tooltip = DescriptorsUtils.formatFormText(elem_desc.getTooltip(), - elem_desc, - Sdk.getCurrent().getDocumentationBaseUrl()); - } else { - tooltip = elem_desc.getTooltip(); - } - - try { - FormText text = SectionHelper.createFormText(masterTable, toolkit, - true /* isHtml */, tooltip, true /* setupLayoutData */); - text.addHyperlinkListener(mTree.getEditor().createHyperlinkListener()); - Image icon = elem_desc.getIcon(); - if (icon != null) { - text.setImage(DescriptorsUtils.IMAGE_KEY, icon); - } - } catch(Exception e) { - // The FormText parser is really really basic and will fail as soon as the - // HTML javadoc is ever so slightly malformatted. - AdtPlugin.log(e, - "Malformed javadoc, rejected by FormText for node %1$s: '%2$s'", //$NON-NLS-1$ - ui_node.getDescriptor().getXmlName(), - tooltip); - - // Fallback to a pure text tooltip, no fancy HTML - tooltip = DescriptorsUtils.formatTooltip(elem_desc.getTooltip()); - Label label = SectionHelper.createLabel(masterTable, toolkit, - tooltip, tooltip); - } - } - - Composite table = useSubsections ? null : masterTable; - - for (AttributeDescriptor attr_desc : attr_desc_list) { - if (attr_desc instanceof XmlnsAttributeDescriptor) { - // Do not show hidden attributes - continue; - } else if (table == null || attr_desc instanceof SeparatorAttributeDescriptor) { - String title = null; - if (attr_desc instanceof SeparatorAttributeDescriptor) { - // xmlName is actually the label of the separator - title = attr_desc.getXmlLocalName(); - } else { - title = String.format("Attributes from %1$s", elem_desc.getUiName()); - } - - table = createSubSectionTable(toolkit, masterTable, title); - if (attr_desc instanceof SeparatorAttributeDescriptor) { - continue; - } - } - - UiAttributeNode ui_attr = ui_node.findUiAttribute(attr_desc); - - if (ui_attr != null) { - ui_attr.createUiControl(table, managedForm); - - if (ui_attr.getCurrentValue() != null && - ui_attr.getCurrentValue().length() > 0) { - ((Section) table.getParent()).setExpanded(true); - } - } else { - // The XML has an extra unknown attribute. - // This is not expected to happen so it is ignored. - AdtPlugin.log(IStatus.INFO, - "Attribute %1$s not declared in node %2$s, ignored.", //$NON-NLS-1$ - attr_desc.getXmlLocalName(), - ui_node.getDescriptor().getXmlName()); - } - } - - // Create a sub-section for the unknown attributes. - // It is initially hidden till there are some attributes to show here. - final Composite unknownTable = createSubSectionTable(toolkit, masterTable, - "Unknown XML Attributes"); - unknownTable.getParent().setVisible(false); // set section to not visible - final HashSet<UiAttributeNode> reference = new HashSet<UiAttributeNode>(); - - final IUiUpdateListener updateListener = new IUiUpdateListener() { - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) { - if (state == UiUpdateState.ATTR_UPDATED) { - updateUnknownAttributesSection(ui_node, unknownTable, managedForm, - reference); - } - } - }; - ui_node.addUpdateListener(updateListener); - - // remove the listener when the UI is disposed - unknownTable.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - ui_node.removeUpdateListener(updateListener); - } - }); - - updateUnknownAttributesSection(ui_node, unknownTable, managedForm, reference); - - mMasterSection.getParent().pack(true /* changed */); - } - } - - /** - * Create a sub Section and its embedding wrapper table with 2 columns. - * @return The table, child of a new section. - */ - private Composite createSubSectionTable(FormToolkit toolkit, - Composite masterTable, String title) { - - // The Section composite seems to ignore colspan when assigned a TableWrapData so - // if the parent is a table with more than one column an extra table with one column - // is inserted to respect colspan. - int parentNumCol = ((TableWrapLayout) masterTable.getLayout()).numColumns; - if (parentNumCol > 1) { - masterTable = SectionHelper.createTableLayout(masterTable, toolkit, 1); - TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB); - twd.maxWidth = AndroidEditor.TEXT_WIDTH_HINT; - twd.colspan = parentNumCol; - masterTable.setLayoutData(twd); - } - - Composite table; - Section section = toolkit.createSection(masterTable, - Section.TITLE_BAR | Section.TWISTIE); - - // Add an expansion listener that will trigger a reflow on the parent - // ScrolledPageBook (which is actually a SharedScrolledComposite). This will - // recompute the correct size and adjust the scrollbar as needed. - section.addExpansionListener(new IExpansionListener() { - public void expansionStateChanged(ExpansionEvent e) { - reflowMasterSection(); - } - - public void expansionStateChanging(ExpansionEvent e) { - // pass - } - }); - - section.setText(title); - section.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, - TableWrapData.TOP)); - table = SectionHelper.createTableLayout(section, toolkit, 2 /* numColumns */); - return table; - } - - /** - * Reflow the parent ScrolledPageBook (which is actually a SharedScrolledComposite). - * This will recompute the correct size and adjust the scrollbar as needed. - */ - private void reflowMasterSection() { - for(Composite c = mMasterSection; c != null; c = c.getParent()) { - if (c instanceof SharedScrolledComposite) { - ((SharedScrolledComposite) c).reflow(true /* flushCache */); - break; - } - } - } - - /** - * Updates the unknown attributes section for the UI Node. - */ - private void updateUnknownAttributesSection(UiElementNode ui_node, - final Composite unknownTable, final IManagedForm managedForm, - HashSet<UiAttributeNode> reference) { - Collection<UiAttributeNode> ui_attrs = ui_node.getUnknownUiAttributes(); - Section section = ((Section) unknownTable.getParent()); - boolean needs_reflow = false; - - // The table was created hidden, show it if there are unknown attributes now - if (ui_attrs.size() > 0 && !section.isVisible()) { - section.setVisible(true); - needs_reflow = true; - } - - // Compare the new attribute set with the old "reference" one - boolean has_differences = ui_attrs.size() != reference.size(); - if (!has_differences) { - for (UiAttributeNode ui_attr : ui_attrs) { - if (!reference.contains(ui_attr)) { - has_differences = true; - break; - } - } - } - - if (has_differences) { - needs_reflow = true; - reference.clear(); - - // Remove all children of the table - for (Control c : unknownTable.getChildren()) { - c.dispose(); - } - - // Recreate all attributes UI - for (UiAttributeNode ui_attr : ui_attrs) { - reference.add(ui_attr); - ui_attr.createUiControl(unknownTable, managedForm); - - if (ui_attr.getCurrentValue() != null && ui_attr.getCurrentValue().length() > 0) { - section.setExpanded(true); - } - } - } - - if (needs_reflow) { - reflowMasterSection(); - } - } - - /** - * Marks the part dirty. Called as a result of user interaction with the widgets in the - * section. - */ - private void markDirty() { - if (!mIsDirty) { - mIsDirty = true; - mManagedForm.dirtyStateChanged(); - } - } -} - - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiModelTreeContentProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiModelTreeContentProvider.java deleted file mode 100644 index 9f34d9e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiModelTreeContentProvider.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui.tree; - -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -import java.util.ArrayList; - -/** - * UiModelTreeContentProvider is a trivial implementation of {@link ITreeContentProvider} - * where elements are expected to be instances of {@link UiElementNode}. - */ -class UiModelTreeContentProvider implements ITreeContentProvider { - - /** The root {@link UiElementNode} which contains all the elements that are to be - * manipulated by this tree view. In general this is the manifest UI node. */ - private UiElementNode mUiRootNode; - /** The descriptor of the elements to be displayed as root in this tree view. All elements - * of the same type in the root will be displayed. */ - private ElementDescriptor[] mDescriptorFilters; - - public UiModelTreeContentProvider(UiElementNode uiRootNode, - ElementDescriptor[] descriptorFilters) { - mUiRootNode = uiRootNode; - mDescriptorFilters = descriptorFilters; - } - - /* (non-java doc) - * Returns all the UI node children of the given element or null if not the right kind - * of object. */ - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof UiElementNode) { - UiElementNode node = (UiElementNode) parentElement; - return node.getUiChildren().toArray(); - } - return null; - } - - /* (non-java doc) - * Returns the parent of a given UI node or null if it's a root node or it's not the - * right kind of node. */ - public Object getParent(Object element) { - if (element instanceof UiElementNode) { - UiElementNode node = (UiElementNode) element; - return node.getUiParent(); - } - return null; - } - - /* (non-java doc) - * Returns true if the UI node has any UI children nodes. */ - public boolean hasChildren(Object element) { - if (element instanceof UiElementNode) { - UiElementNode node = (UiElementNode) element; - return node.getUiChildren().size() > 0; - } - return false; - } - - /* (non-java doc) - * Get root elements for the tree. These are all the UI nodes that - * match the filter descriptor in the current root node. - * <p/> - * Although not documented, it seems this method should not return null. - * At worse, it should return new Object[0]. - * <p/> - * inputElement is not currently used. The root node and the filter are given - * by the enclosing class. - */ - public Object[] getElements(Object inputElement) { - ArrayList<UiElementNode> roots = new ArrayList<UiElementNode>(); - if (mUiRootNode != null) { - for (UiElementNode ui_node : mUiRootNode.getUiChildren()) { - if (mDescriptorFilters == null || mDescriptorFilters.length == 0) { - roots.add(ui_node); - } else { - for (ElementDescriptor filter : mDescriptorFilters) { - if (ui_node.getDescriptor() == filter) { - roots.add(ui_node); - } - } - } - } - } - - return roots.toArray(); - } - - public void dispose() { - // pass - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // pass - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiModelTreeLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiModelTreeLabelProvider.java deleted file mode 100644 index 273a30b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiModelTreeLabelProvider.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui.tree; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.ui.ErrorImageComposite; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.swt.graphics.Image; - -/** - * UiModelTreeLabelProvider is a trivial implementation of {@link ILabelProvider} - * where elements are expected to derive from {@link UiElementNode} or - * from {@link ElementDescriptor}. - * - * It is used by both the master tree viewer and by the list in the Add... selection dialog. - */ -public class UiModelTreeLabelProvider implements ILabelProvider { - - public UiModelTreeLabelProvider() { - } - - /** - * Returns the element's logo with a fallback on the android logo. - */ - public Image getImage(Object element) { - ElementDescriptor desc = null; - if (element instanceof ElementDescriptor) { - Image img = ((ElementDescriptor) element).getIcon(); - if (img != null) { - return img; - } - } else if (element instanceof UiElementNode) { - UiElementNode node = (UiElementNode) element; - desc = node.getDescriptor(); - if (desc != null) { - Image img = desc.getIcon(); - if (img != null) { - if (node.hasError()) { - //TODO: cache image - return new ErrorImageComposite(img).createImage(); - } else { - return img; - } - } - } - } - return AdtPlugin.getAndroidLogo(); - } - - /** - * Uses UiElementNode.shortDescription for the label for this tree item. - */ - public String getText(Object element) { - if (element instanceof ElementDescriptor) { - ElementDescriptor desc = (ElementDescriptor) element; - return desc.getUiName(); - } else if (element instanceof UiElementNode) { - UiElementNode node = (UiElementNode) element; - return node.getShortDescription(); - } - return element.toString(); - } - - public void addListener(ILabelProviderListener listener) { - // pass - } - - public void dispose() { - // pass - } - - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - public void removeListener(ILabelProviderListener listener) { - // pass - } -} - - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java deleted file mode 100644 index e3255d9..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.ui.tree; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.ide.eclipse.editors.ui.SectionHelper.ManifestSectionPart; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.action.ToolBarManager; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.ITreeSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerComparator; -import org.eclipse.jface.viewers.ViewerFilter; -import org.eclipse.swt.SWT; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.swt.widgets.ToolBar; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.ui.forms.DetailsPart; -import org.eclipse.ui.forms.IDetailsPage; -import org.eclipse.ui.forms.IDetailsPageProvider; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.MasterDetailsBlock; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.Section; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * {@link UiTreeBlock} is a {@link MasterDetailsBlock} which displays a tree view for - * a specific set of {@link UiElementNode}. - * <p/> - * For a given UI element node, the tree view displays all first-level children that - * match a given type (given by an {@link ElementDescriptor}. All children from these - * nodes are also displayed. - * <p/> - * In the middle next to the tree are some controls to add or delete tree nodes. - * On the left is a details part that displays all the visible UI attributes for a given - * selected UI element node. - */ -public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml { - - /** Height hint for the tree view. Helps the grid layout resize properly on smaller screens. */ - private static final int TREE_HEIGHT_HINT = 50; - - /** Container editor */ - AndroidEditor mEditor; - /** The root {@link UiElementNode} which contains all the elements that are to be - * manipulated by this tree view. In general this is the manifest UI node. */ - private UiElementNode mUiRootNode; - /** The descriptor of the elements to be displayed as root in this tree view. All elements - * of the same type in the root will be displayed. */ - private ElementDescriptor[] mDescriptorFilters; - /** The title for the master-detail part (displayed on the top "tab" on top of the tree) */ - private String mTitle; - /** The description for the master-detail part (displayed on top of the tree view) */ - private String mDescription; - /** The master-detail part, composed of a main tree and an auxiliary detail part */ - private ManifestSectionPart mMasterPart; - /** The tree viewer in the master-detail part */ - private TreeViewer mTreeViewer; - /** The "add" button for the tree view */ - private Button mAddButton; - /** The "remove" button for the tree view */ - private Button mRemoveButton; - /** The "up" button for the tree view */ - private Button mUpButton; - /** The "down" button for the tree view */ - private Button mDownButton; - /** The Managed Form used to create the master part */ - private IManagedForm mManagedForm; - /** Reference to the details part of the tree master block. */ - private DetailsPart mDetailsPart; - /** Reference to the clipboard for copy-paste */ - private Clipboard mClipboard; - /** Listener to refresh the tree viewer when the parent's node has been updated */ - private IUiUpdateListener mUiRefreshListener; - /** Listener to enable/disable the UI based on the application node's presence */ - private IUiUpdateListener mUiEnableListener; - /** An adapter/wrapper to use the add/remove/up/down tree edit actions. */ - private UiTreeActions mUiTreeActions; - /** - * True if the root node can be created on-demand (i.e. as needed as - * soon as children exist). False if an external entity controls the existence of the - * root node. In practise, this is false for the manifest application page (the actual - * "application" node is managed by the ApplicationToggle part) whereas it is true - * for all other tree pages. - */ - private final boolean mAutoCreateRoot; - - - /** - * Creates a new {@link MasterDetailsBlock} that will display all UI nodes matching the - * given filter in the given root node. - * - * @param editor The parent manifest editor. - * @param uiRootNode The root {@link UiElementNode} which contains all the elements that are - * to be manipulated by this tree view. In general this is the manifest UI node or the - * application UI node. This cannot be null. - * @param autoCreateRoot True if the root node can be created on-demand (i.e. as needed as - * soon as children exist). False if an external entity controls the existence of the - * root node. In practise, this is false for the manifest application page (the actual - * "application" node is managed by the ApplicationToggle part) whereas it is true - * for all other tree pages. - * @param descriptorFilters A list of descriptors of the elements to be displayed as root in - * this tree view. Use null or an empty list to accept any kind of node. - * @param title Title for the section - * @param description Description for the section - */ - public UiTreeBlock(AndroidEditor editor, - UiElementNode uiRootNode, - boolean autoCreateRoot, - ElementDescriptor[] descriptorFilters, - String title, - String description) { - mEditor = editor; - mUiRootNode = uiRootNode; - mAutoCreateRoot = autoCreateRoot; - mDescriptorFilters = descriptorFilters; - mTitle = title; - mDescription = description; - } - - /** @returns The container editor */ - AndroidEditor getEditor() { - return mEditor; - } - - /** @returns The reference to the clipboard for copy-paste */ - Clipboard getClipboard() { - return mClipboard; - } - - /** @returns The master-detail part, composed of a main tree and an auxiliary detail part */ - ManifestSectionPart getMasterPart() { - return mMasterPart; - } - - @Override - protected void createMasterPart(final IManagedForm managedForm, Composite parent) { - FormToolkit toolkit = managedForm.getToolkit(); - - mManagedForm = managedForm; - mMasterPart = new ManifestSectionPart(parent, toolkit); - Section section = mMasterPart.getSection(); - section.setText(mTitle); - section.setDescription(mDescription); - section.setLayout(new GridLayout()); - section.setLayoutData(new GridData(GridData.FILL_BOTH)); - - Composite grid = SectionHelper.createGridLayout(section, toolkit, 2); - - Tree tree = createTreeViewer(toolkit, grid, managedForm); - createButtons(toolkit, grid); - createTreeContextMenu(tree); - createSectionActions(section, toolkit); - } - - private void createSectionActions(Section section, FormToolkit toolkit) { - ToolBarManager manager = new ToolBarManager(SWT.FLAT); - manager.removeAll(); - - ToolBar toolbar = manager.createControl(section); - section.setTextClient(toolbar); - - ElementDescriptor[] descs = mDescriptorFilters; - if (descs == null && mUiRootNode != null) { - descs = mUiRootNode.getDescriptor().getChildren(); - } - - if (descs != null && descs.length > 1) { - for (ElementDescriptor desc : descs) { - manager.add(new DescriptorFilterAction(desc)); - } - } - - manager.add(new TreeSortAction()); - - manager.update(true /*force*/); - } - - /** - * Creates the tree and its viewer - * @return The tree control - */ - private Tree createTreeViewer(FormToolkit toolkit, Composite grid, - final IManagedForm managedForm) { - // Note: we *could* use a FilteredTree instead of the Tree+TreeViewer here. - // However the class must be adapted to create an adapted toolkit tree. - final Tree tree = toolkit.createTree(grid, SWT.MULTI); - GridData gd = new GridData(GridData.FILL_BOTH); - gd.widthHint = AndroidEditor.TEXT_WIDTH_HINT; - gd.heightHint = TREE_HEIGHT_HINT; - tree.setLayoutData(gd); - - mTreeViewer = new TreeViewer(tree); - mTreeViewer.setContentProvider(new UiModelTreeContentProvider( - mUiRootNode, mDescriptorFilters)); - mTreeViewer.setLabelProvider(new UiModelTreeLabelProvider()); - mTreeViewer.setInput("unused"); //$NON-NLS-1$ - - // Create a listener that reacts to selections on the tree viewer. - // When a selection is made, ask the managed form to propagate an event to - // all parts in the managed form. - // This is picked up by UiElementDetail.selectionChanged(). - mTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - managedForm.fireSelectionChanged(mMasterPart, event.getSelection()); - adjustTreeButtons(event.getSelection()); - } - }); - - // Create three listeners: - // - One to refresh the tree viewer when the parent's node has been updated - // - One to refresh the tree viewer when the framework resources have changed - // - One to enable/disable the UI based on the application node's presence. - mUiRefreshListener = new IUiUpdateListener() { - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) { - mTreeViewer.refresh(); - } - }; - - mUiEnableListener = new IUiUpdateListener() { - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) { - // The UiElementNode for the application XML node always exists, even - // if there is no corresponding XML node in the XML file. - // - // Normally, we enable the UI here if the XML node is not null. - // - // However if mAutoCreateRoot is true, the root node will be created on-demand - // so the tree/block is always enabled. - boolean exists = mAutoCreateRoot || (ui_node.getXmlNode() != null); - if (mMasterPart != null) { - Section section = mMasterPart.getSection(); - if (section.getEnabled() != exists) { - section.setEnabled(exists); - for (Control c : section.getChildren()) { - c.setEnabled(exists); - } - } - } - } - }; - - final Runnable resourceRefreshListener = new Runnable() { - public void run() { - // If a details part has been created, we need to "refresh" it too. - if (mDetailsPart != null) { - // The details part does not directly expose access to its internal - // page book. Instead it is possible to resize the page book to 0 and then - // back to its original value, which as the side effect of removing all - // existing cached pages. - int limit = mDetailsPart.getPageLimit(); - mDetailsPart.setPageLimit(0); - mDetailsPart.setPageLimit(limit); - } - // Refresh the tree, preserving the selection if possible. - mTreeViewer.refresh(); - } - }; - - // Setup the listeners - changeRootAndDescriptors(mUiRootNode, mDescriptorFilters, false /* refresh */); - - // Listen on resource framework changes to refresh the tree - AdtPlugin.getDefault().addResourceChangedListener(resourceRefreshListener); - - // Remove listeners when the tree widget gets disposed. - tree.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - UiElementNode node = mUiRootNode.getUiParent() != null ? - mUiRootNode.getUiParent() : - mUiRootNode; - - node.removeUpdateListener(mUiRefreshListener); - mUiRootNode.removeUpdateListener(mUiEnableListener); - - AdtPlugin.getDefault().removeResourceChangedListener(resourceRefreshListener); - if (mClipboard != null) { - mClipboard.dispose(); - mClipboard = null; - } - } - }); - - // Get a new clipboard reference. It is disposed when the tree is disposed. - mClipboard = new Clipboard(tree.getDisplay()); - - return tree; - } - - /** - * Changes the UI root node and the descriptor filters of the tree. - * <p/> - * This removes the listeners attached to the old root node and reattaches them to the - * new one. - * - * @param uiRootNode The root {@link UiElementNode} which contains all the elements that are - * to be manipulated by this tree view. In general this is the manifest UI node or the - * application UI node. This cannot be null. - * @param descriptorFilters A list of descriptors of the elements to be displayed as root in - * this tree view. Use null or an empty list to accept any kind of node. - * @param forceRefresh If tree, forces the tree to refresh - */ - public void changeRootAndDescriptors(UiElementNode uiRootNode, - ElementDescriptor[] descriptorFilters, boolean forceRefresh) { - UiElementNode node; - - // Remove previous listeners if any - if (mUiRootNode != null) { - node = mUiRootNode.getUiParent() != null ? mUiRootNode.getUiParent() : mUiRootNode; - node.removeUpdateListener(mUiRefreshListener); - mUiRootNode.removeUpdateListener(mUiEnableListener); - } - - mUiRootNode = uiRootNode; - mDescriptorFilters = descriptorFilters; - - // Listen on structural changes on the root node of the tree - // If the node has a parent, listen on the parent instead. - node = mUiRootNode.getUiParent() != null ? mUiRootNode.getUiParent() : mUiRootNode; - node.addUpdateListener(mUiRefreshListener); - - // Use the root node to listen to its presence. - mUiRootNode.addUpdateListener(mUiEnableListener); - - // Initialize the enabled/disabled state - mUiEnableListener.uiElementNodeUpdated(mUiRootNode, null /* state, not used */); - - if (forceRefresh) { - mTreeViewer.refresh(); - } - - createSectionActions(mMasterPart.getSection(), mManagedForm.getToolkit()); - } - - /** - * Creates the buttons next to the tree. - */ - private void createButtons(FormToolkit toolkit, Composite grid) { - - mUiTreeActions = new UiTreeActions(); - - Composite button_grid = SectionHelper.createGridLayout(grid, toolkit, 1); - button_grid.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING)); - mAddButton = toolkit.createButton(button_grid, "Add...", SWT.PUSH); - SectionHelper.addControlTooltip(mAddButton, "Adds a new element."); - mAddButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | - GridData.VERTICAL_ALIGN_BEGINNING)); - - mAddButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - doTreeAdd(); - } - }); - - mRemoveButton = toolkit.createButton(button_grid, "Remove...", SWT.PUSH); - SectionHelper.addControlTooltip(mRemoveButton, "Removes an existing selected element."); - mRemoveButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mRemoveButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - doTreeRemove(); - } - }); - - mUpButton = toolkit.createButton(button_grid, "Up", SWT.PUSH); - SectionHelper.addControlTooltip(mRemoveButton, "Moves the selected element up."); - mUpButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mUpButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - doTreeUp(); - } - }); - - mDownButton = toolkit.createButton(button_grid, "Down", SWT.PUSH); - SectionHelper.addControlTooltip(mRemoveButton, "Moves the selected element down."); - mDownButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - mDownButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - doTreeDown(); - } - }); - - adjustTreeButtons(TreeSelection.EMPTY); - } - - private void createTreeContextMenu(Tree tree) { - MenuManager menuManager = new MenuManager(); - menuManager.setRemoveAllWhenShown(true); - menuManager.addMenuListener(new IMenuListener() { - /** - * The menu is about to be shown. The menu manager has already been - * requested to remove any existing menu item. This method gets the - * tree selection and if it is of the appropriate type it re-creates - * the necessary actions. - */ - public void menuAboutToShow(IMenuManager manager) { - ISelection selection = mTreeViewer.getSelection(); - if (!selection.isEmpty() && selection instanceof ITreeSelection) { - ArrayList<UiElementNode> selected = filterSelection((ITreeSelection) selection); - doCreateMenuAction(manager, selected); - return; - } - doCreateMenuAction(manager, null /* ui_node */); - } - }); - Menu contextMenu = menuManager.createContextMenu(tree); - tree.setMenu(contextMenu); - } - - /** - * Adds the menu actions to the context menu when the given UI node is selected in - * the tree view. - * - * @param manager The context menu manager - * @param selected The UI nodes selected in the tree. Can be null, in which case the root - * is to be modified. - */ - private void doCreateMenuAction(IMenuManager manager, ArrayList<UiElementNode> selected) { - if (selected != null) { - boolean hasXml = false; - for (UiElementNode uiNode : selected) { - if (uiNode.getXmlNode() != null) { - hasXml = true; - break; - } - } - - if (hasXml) { - manager.add(new CopyCutAction(getEditor(), getClipboard(), - null, selected, true /* cut */)); - manager.add(new CopyCutAction(getEditor(), getClipboard(), - null, selected, false /* cut */)); - - // Can't paste with more than one element selected (the selection is the target) - if (selected.size() <= 1) { - // Paste is not valid if it would add a second element on a terminal element - // which parent is a document -- an XML document can only have one child. This - // means paste is valid if the current UI node can have children or if the - // parent is not a document. - UiElementNode ui_root = selected.get(0).getUiRoot(); - if (ui_root.getDescriptor().hasChildren() || - !(ui_root.getUiParent() instanceof UiDocumentNode)) { - manager.add(new PasteAction(getEditor(), getClipboard(), selected.get(0))); - } - } - manager.add(new Separator()); - } - } - - // Append "add" and "remove" actions. They do the same thing as the add/remove - // buttons on the side. - Action action; - IconFactory factory = IconFactory.getInstance(); - - // "Add" makes sense only if there's 0 or 1 item selected since the - // one selected item becomes the target. - if (selected == null || selected.size() <= 1) { - manager.add(new Action("Add...", factory.getImageDescriptor("add")) { //$NON-NLS-1$ - @Override - public void run() { - super.run(); - doTreeAdd(); - } - }); - } - - if (selected != null) { - if (selected != null) { - manager.add(new Action("Remove", factory.getImageDescriptor("delete")) { //$NON-NLS-1$ - @Override - public void run() { - super.run(); - doTreeRemove(); - } - }); - } - manager.add(new Separator()); - - manager.add(new Action("Up", factory.getImageDescriptor("up")) { //$NON-NLS-1$ - @Override - public void run() { - super.run(); - doTreeUp(); - } - }); - manager.add(new Action("Down", factory.getImageDescriptor("down")) { //$NON-NLS-1$ - @Override - public void run() { - super.run(); - doTreeDown(); - } - }); - } - } - - - /** - * This is called by the tree when a selection is made. - * It enables/disables the buttons associated with the tree depending on the current - * selection. - * - * @param selection The current tree selection (same as mTreeViewer.getSelection()) - */ - private void adjustTreeButtons(ISelection selection) { - mRemoveButton.setEnabled(!selection.isEmpty() && selection instanceof ITreeSelection); - mUpButton.setEnabled(!selection.isEmpty() && selection instanceof ITreeSelection); - mDownButton.setEnabled(!selection.isEmpty() && selection instanceof ITreeSelection); - } - - /** - * An adapter/wrapper to use the add/remove/up/down tree edit actions. - */ - private class UiTreeActions extends UiActions { - @Override - protected UiElementNode getRootNode() { - return mUiRootNode; - } - - @Override - protected void selectUiNode(UiElementNode uiNodeToSelect) { - // Select the new item - if (uiNodeToSelect != null) { - LinkedList<UiElementNode> segments = new LinkedList<UiElementNode>(); - for (UiElementNode ui_node = uiNodeToSelect; ui_node != mUiRootNode; - ui_node = ui_node.getUiParent()) { - segments.add(0, ui_node); - } - mTreeViewer.setSelection(new TreeSelection(new TreePath(segments.toArray()))); - } - } - - @Override - public void commitPendingXmlChanges() { - commitManagedForm(); - } - } - - /** - * Filters an ITreeSelection to only keep the {@link UiElementNode}s (in case there's - * something else in there). - * - * @return A new list of {@link UiElementNode} with at least one item or null. - */ - @SuppressWarnings("unchecked") - private ArrayList<UiElementNode> filterSelection(ITreeSelection selection) { - ArrayList<UiElementNode> selected = new ArrayList<UiElementNode>(); - - for (Iterator it = selection.iterator(); it.hasNext(); ) { - Object selectedObj = it.next(); - - if (selectedObj instanceof UiElementNode) { - selected.add((UiElementNode) selectedObj); - } - } - - return selected.size() > 0 ? selected : null; - } - - /** - * Called when the "Add..." button next to the tree view is selected. - * - * Displays a selection dialog that lets the user select which kind of node - * to create, depending on the current selection. - */ - private void doTreeAdd() { - UiElementNode ui_node = mUiRootNode; - ISelection selection = mTreeViewer.getSelection(); - if (!selection.isEmpty() && selection instanceof ITreeSelection) { - ITreeSelection tree_selection = (ITreeSelection) selection; - Object first = tree_selection.getFirstElement(); - if (first != null && first instanceof UiElementNode) { - ui_node = (UiElementNode) first; - } - } - - mUiTreeActions.doAdd( - ui_node, - mDescriptorFilters, - mTreeViewer.getControl().getShell(), - (ILabelProvider) mTreeViewer.getLabelProvider()); - } - - /** - * Called when the "Remove" button is selected. - * - * If the tree has a selection, remove it. - * This simply deletes the XML node attached to the UI node: when the XML model fires the - * update event, the tree will get refreshed. - */ - protected void doTreeRemove() { - ISelection selection = mTreeViewer.getSelection(); - if (!selection.isEmpty() && selection instanceof ITreeSelection) { - ArrayList<UiElementNode> selected = filterSelection((ITreeSelection) selection); - mUiTreeActions.doRemove(selected, mTreeViewer.getControl().getShell()); - } - } - - /** - * Called when the "Up" button is selected. - * <p/> - * If the tree has a selection, move it up, either in the child list or as the last child - * of the previous parent. - */ - protected void doTreeUp() { - ISelection selection = mTreeViewer.getSelection(); - if (!selection.isEmpty() && selection instanceof ITreeSelection) { - ArrayList<UiElementNode> selected = filterSelection((ITreeSelection) selection); - mUiTreeActions.doUp(selected); - } - } - - /** - * Called when the "Down" button is selected. - * - * If the tree has a selection, move it down, either in the same child list or as the - * first child of the next parent. - */ - protected void doTreeDown() { - ISelection selection = mTreeViewer.getSelection(); - if (!selection.isEmpty() && selection instanceof ITreeSelection) { - ArrayList<UiElementNode> selected = filterSelection((ITreeSelection) selection); - mUiTreeActions.doDown(selected); - } - } - - /** - * Commits the current managed form (the one associated with our master part). - * As a side effect, this will commit the current UiElementDetails page. - */ - void commitManagedForm() { - if (mManagedForm != null) { - mManagedForm.commit(false /* onSave */); - } - } - - /* Implements ICommitXml for CopyCutAction */ - public void commitPendingXmlChanges() { - commitManagedForm(); - } - - @Override - protected void createToolBarActions(IManagedForm managedForm) { - // Pass. Not used, toolbar actions are defined by createSectionActions(). - } - - @Override - protected void registerPages(DetailsPart detailsPart) { - // Keep a reference on the details part (the super class doesn't provide a getter - // for it.) - mDetailsPart = detailsPart; - - // The page selection mechanism does not use pages registered by association with - // a node class. Instead it uses a custom details page provider that provides a - // new UiElementDetail instance for each node instance. A limit of 5 pages is - // then set (the value is arbitrary but should be reasonable) for the internal - // page book. - detailsPart.setPageLimit(5); - - final UiTreeBlock tree = this; - - detailsPart.setPageProvider(new IDetailsPageProvider() { - public IDetailsPage getPage(Object key) { - if (key instanceof UiElementNode) { - return new UiElementDetail(tree); - } - return null; - } - - public Object getPageKey(Object object) { - return object; // use node object as key - } - }); - } - - /** - * An alphabetic sort action for the tree viewer. - */ - private class TreeSortAction extends Action { - - private ViewerComparator mComparator; - - public TreeSortAction() { - super("Sorts elements alphabetically.", AS_CHECK_BOX); - setImageDescriptor(IconFactory.getInstance().getImageDescriptor("az_sort")); //$NON-NLS-1$ - - if (mTreeViewer != null) { - boolean is_sorted = mTreeViewer.getComparator() != null; - setChecked(is_sorted); - } - } - - /** - * Called when the button is selected. Toggles the tree viewer comparator. - */ - @Override - public void run() { - if (mTreeViewer == null) { - notifyResult(false /*success*/); - return; - } - - ViewerComparator comp = mTreeViewer.getComparator(); - if (comp != null) { - // Tree is currently sorted. - // Save currently comparator and remove it - mComparator = comp; - mTreeViewer.setComparator(null); - } else { - // Tree is not currently sorted. - // Reuse or add a new comparator. - if (mComparator == null) { - mComparator = new ViewerComparator(); - } - mTreeViewer.setComparator(mComparator); - } - - notifyResult(true /*success*/); - } - } - - /** - * A filter on descriptor for the tree viewer. - * <p/> - * The tree viewer will contain many of these actions and only one can be enabled at a - * given time. When no action is selected, everything is displayed. - * <p/> - * Since "radio"-like actions do not allow for unselecting all of them, we manually - * handle the exclusive radio button-like property: when an action is selected, it manually - * removes all other actions as needed. - */ - private class DescriptorFilterAction extends Action { - - private final ElementDescriptor mDescriptor; - private ViewerFilter mFilter; - - public DescriptorFilterAction(ElementDescriptor descriptor) { - super(String.format("Displays only %1$s elements.", descriptor.getUiName()), - AS_CHECK_BOX); - - mDescriptor = descriptor; - setImageDescriptor(descriptor.getImageDescriptor()); - } - - /** - * Called when the button is selected. - * <p/> - * Find any existing {@link DescriptorFilter}s and remove them. Install ours. - */ - @Override - public void run() { - super.run(); - - if (isChecked()) { - if (mFilter == null) { - // create filter when required - mFilter = new DescriptorFilter(this); - } - - // we add our filter first, otherwise the UI might show the full list - mTreeViewer.addFilter(mFilter); - - // Then remove the any other filters except ours. There should be at most - // one other filter, since that's how the actions are made to look like - // exclusive radio buttons. - for (ViewerFilter filter : mTreeViewer.getFilters()) { - if (filter instanceof DescriptorFilter && filter != mFilter) { - DescriptorFilterAction action = ((DescriptorFilter) filter).getAction(); - action.setChecked(false); - mTreeViewer.removeFilter(filter); - } - } - } else if (mFilter != null){ - mTreeViewer.removeFilter(mFilter); - } - } - - /** - * Filters the tree viewer for the given descriptor. - * <p/> - * The filter is linked to the action so that an action can iterate through the list - * of filters and un-select the actions. - */ - private class DescriptorFilter extends ViewerFilter { - - private final DescriptorFilterAction mAction; - - public DescriptorFilter(DescriptorFilterAction action) { - mAction = action; - } - - public DescriptorFilterAction getAction() { - return mAction; - } - - /** - * Returns true if an element should be displayed, that if the element or - * any of its parent matches the requested descriptor. - */ - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) { - while (element instanceof UiElementNode) { - UiElementNode uiNode = (UiElementNode)element; - if (uiNode.getDescriptor() == mDescriptor) { - return true; - } - element = uiNode.getUiParent(); - } - return false; - } - } - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/IUiSettableAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/IUiSettableAttributeNode.java deleted file mode 100644 index 7fe44da..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/IUiSettableAttributeNode.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 - * - * 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.editors.uimodel; - -/** - * This interface decoration indicates that a given UiAttributeNode can both - * set and get its current value. - */ -public interface IUiSettableAttributeNode { - - /** Returns the current value of the node. */ - public String getCurrentValue(); - - /** Sets the current value of the node. Cannot be null (use an empty string). */ - public void setCurrentValue(String value); - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/IUiUpdateListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/IUiUpdateListener.java deleted file mode 100644 index 12cb31b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/IUiUpdateListener.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - - -/** - * Listen to update notifications in UI nodes. - */ -public interface IUiUpdateListener { - - /** Update state of the UI node */ - public enum UiUpdateState { - /** The node's attributes have been updated. They may or may not actually have changed. */ - ATTR_UPDATED, - /** The node sub-structure (i.e. child nodes) has changed */ - CHILDREN_CHANGED, - /** The XML counterpart for the UI node has just been created. */ - CREATED, - /** The XML counterpart for the UI node has just been deleted. - * Note that mandatory UI nodes are never actually deleted. */ - DELETED - } - - /** - * Indicates that an UiElementNode has been updated. - * <p/> - * This happens when an {@link UiElementNode} is refreshed to match the - * XML model. The actual UI element node may or may not have changed. - * - * @param ui_node The {@link UiElementNode} being updated. - */ - public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiAbstractTextAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiAbstractTextAttributeNode.java deleted file mode 100644 index 4a9fbb1..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiAbstractTextAttributeNode.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; - -import org.w3c.dom.Node; - -/** - * Represents an XML attribute in that can be modified using a simple text field - * in the XML editor's user interface. - * <p/> - * The XML attribute has no default value. When unset, the text field is blank. - * When updating the XML, if the field is empty, the attribute will be removed - * from the XML element. - * <p/> - * See {@link UiAttributeNode} for more information. - */ -public abstract class UiAbstractTextAttributeNode extends UiAttributeNode - implements IUiSettableAttributeNode { - - protected static final String DEFAULT_VALUE = ""; //$NON-NLS-1$ - - /** Prevent internal listener from firing when internally modifying the text */ - private boolean mInternalTextModification; - /** Last value read from the XML model. Cannot be null. */ - private String mCurrentValue = DEFAULT_VALUE; - - public UiAbstractTextAttributeNode(AttributeDescriptor attributeDescriptor, - UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /** Returns the current value of the node. */ - @Override - public final String getCurrentValue() { - return mCurrentValue; - } - - /** Sets the current value of the node. Cannot be null (use an empty string). */ - public final void setCurrentValue(String value) { - mCurrentValue = value; - } - - /** Returns if the attribute node is valid, and its UI has been created. */ - public abstract boolean isValid(); - - /** Returns the text value present in the UI. */ - public abstract String getTextWidgetValue(); - - /** Sets the text value to be displayed in the UI. */ - public abstract void setTextWidgetValue(String value); - - - /** - * Updates the current text field's value when the XML has changed. - * <p/> - * The caller doesn't really know if attributes have changed, - * so it will call this to refresh the attribute anyway. The value - * is only set if it has changed. - * <p/> - * This also resets the "dirty" flag. - */ - @Override - public void updateValue(Node xml_attribute_node) { - mCurrentValue = DEFAULT_VALUE; - if (xml_attribute_node != null) { - mCurrentValue = xml_attribute_node.getNodeValue(); - } - - if (isValid() && !getTextWidgetValue().equals(mCurrentValue)) { - try { - mInternalTextModification = true; - setTextWidgetValue(mCurrentValue); - setDirty(false); - } finally { - mInternalTextModification = false; - } - } - } - - /* (non-java doc) - * Called by the user interface when the editor is saved or its state changed - * and the modified attributes must be committed (i.e. written) to the XML model. - */ - @Override - public void commit() { - UiElementNode parent = getUiParent(); - if (parent != null && isValid() && isDirty()) { - String value = getTextWidgetValue(); - if (parent.commitAttributeToXml(this, value)) { - mCurrentValue = value; - setDirty(false); - } - } - } - - protected final boolean isInInternalTextModification() { - return mInternalTextModification; - } - - protected final void setInInternalTextModification(boolean internalTextModification) { - mInternalTextModification = internalTextModification; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiAttributeNode.java deleted file mode 100644 index 5972f22..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiAttributeNode.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.ui.forms.IManagedForm; -import org.w3c.dom.Node; - -/** - * Represents an XML attribute that can be modified by the XML editor's user interface. - * <p/> - * The characteristics of an {@link UiAttributeNode} are declared by a - * corresponding {@link AttributeDescriptor}. - * <p/> - * This is an abstract class. Derived classes must implement the creation of the UI - * and manage its synchronization with the XML. - */ -public abstract class UiAttributeNode { - - private AttributeDescriptor mDescriptor; - private UiElementNode mUiParent; - private boolean mIsDirty; - private boolean mHasError; - - /** Creates a new {@link UiAttributeNode} linked to a specific {@link AttributeDescriptor} - * and the corresponding runtine {@link UiElementNode} parent. */ - public UiAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { - mDescriptor = attributeDescriptor; - mUiParent = uiParent; - } - - /** Returns the {@link AttributeDescriptor} specific to this UI attribute node */ - public final AttributeDescriptor getDescriptor() { - return mDescriptor; - } - - /** Returns the {@link UiElementNode} that owns this {@link UiAttributeNode} */ - public final UiElementNode getUiParent() { - return mUiParent; - } - - /** Returns the current value of the node. */ - public abstract String getCurrentValue(); - - /** - * @return True if the attribute has been changed since it was last loaded - * from the XML model. - */ - public final boolean isDirty() { - return mIsDirty; - } - - /** - * Sets whether the attribute is dirty and also notifies the editor some part's dirty - * flag as changed. - * <p/> - * Subclasses should set the to true as a result of user interaction with the widgets in - * the section and then should set to false when the commit() method completed. - */ - public void setDirty(boolean isDirty) { - boolean old_value = mIsDirty; - mIsDirty = isDirty; - // TODO: for unknown attributes, getParent() != null && getParent().getEditor() != null - if (old_value != isDirty) { - getUiParent().getEditor().editorDirtyStateChanged(); - } - } - - /** - * Sets the error flag value. - * @param errorFlag the error flag - */ - public final void setHasError(boolean errorFlag) { - mHasError = errorFlag; - } - - /** - * Returns whether this node has errors. - */ - public final boolean hasError() { - return mHasError; - } - - /** - * Called once by the parent user interface to creates the necessary - * user interface to edit this attribute. - * <p/> - * This method can be called more than once in the life cycle of an UI node, - * typically when the UI is part of a master-detail tree, as pages are swapped. - * - * @param parent The composite where to create the user interface. - * @param managedForm The managed form owning this part. - */ - public abstract void createUiControl(Composite parent, IManagedForm managedForm); - - /** - * Used to get a list of all possible values for this UI attribute. - * <p/> - * This is used, among other things, by the XML Content Assists to complete values - * for an attribute. - * <p/> - * Implementations that do not have any known values should return null. - * - * @return A list of possible completion values or null. - */ - public abstract String[] getPossibleValues(); - - /** - * Called when the XML is being loaded or has changed to - * update the value held by this user interface attribute node. - * <p/> - * The XML Node <em>may</em> be null, which denotes that the attribute is not - * specified in the XML model. In general, this means the "default" value of the - * attribute should be used. - * <p/> - * The caller doesn't really know if attributes have changed, - * so it will call this to refresh the attribute anyway. It's up to the - * UI implementation to minimize refreshes. - * - * @param xml_attribute_node - */ - public abstract void updateValue(Node xml_attribute_node); - - /** - * Called by the user interface when the editor is saved or its state changed - * and the modified attributes must be committed (i.e. written) to the XML model. - * <p/> - * Important behaviors: - * <ul> - * <li>The caller *must* have called IStructuredModel.aboutToChangeModel before. - * The implemented methods must assume it is safe to modify the XML model. - * <li>On success, the implementation *must* call setDirty(false). - * <li>On failure, the implementation can fail with an exception, which - * is trapped and logged by the caller, or do nothing, whichever is more - * appropriate. - * </ul> - */ - public abstract void commit(); -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiDocumentNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiDocumentNode.java deleted file mode 100644 index 113738f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiDocumentNode.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.uimodel; - -import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener.UiUpdateState; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -/** - * Represents an XML document node that can be modified by the user interface in the XML editor. - * <p/> - * The structure of a given {@link UiDocumentNode} is declared by a corresponding - * {@link DocumentDescriptor}. - */ -public class UiDocumentNode extends UiElementNode { - - /** - * Creates a new {@link UiDocumentNode} described by a given {@link DocumentDescriptor}. - * - * @param documentDescriptor The {@link DocumentDescriptor} for the XML node. Cannot be null. - */ - public UiDocumentNode(DocumentDescriptor documentDescriptor) { - super(documentDescriptor); - } - - /** - * Computes a short string describing the UI node suitable for tree views. - * Uses the element's attribute "android:name" if present, or the "android:label" one - * followed by the element's name. - * - * @return A short string describing the UI node suitable for tree views. - */ - @Override - public String getShortDescription() { - return "Document"; //$NON-NLS-1$ - } - - /** - * Computes a "breadcrumb trail" description for this node. - * - * @param include_root Whether to include the root (e.g. "Manifest") or not. Has no effect - * when called on the root node itself. - * @return The "breadcrumb trail" description for this node. - */ - @Override - public String getBreadcrumbTrailDescription(boolean include_root) { - return "Document"; //$NON-NLS-1$ - } - - /** - * This method throws an exception when attempted to assign a parent, since XML documents - * cannot have a parent. It is OK to assign null. - */ - @Override - protected void setUiParent(UiElementNode parent) { - if (parent != null) { - // DEBUG. Change to log warning. - throw new UnsupportedOperationException("Documents can't have UI parents"); //$NON-NLS-1$ - } - super.setUiParent(null); - } - - /** - * Populate this element node with all values from the given XML node. - * - * This fails if the given XML node has a different element name -- it won't change the - * type of this ui node. - * - * This method can be both used for populating values the first time and updating values - * after the XML model changed. - * - * @param xml_node The XML node to mirror - * @return Returns true if the XML structure has changed (nodes added, removed or replaced) - */ - @Override - public boolean loadFromXmlNode(Node xml_node) { - boolean structure_changed = (getXmlDocument() != xml_node); - setXmlDocument((Document) xml_node); - structure_changed |= super.loadFromXmlNode(xml_node); - if (structure_changed) { - invokeUiUpdateListeners(UiUpdateState.CHILDREN_CHANGED); - } - return structure_changed; - } - - /** - * This method throws an exception if there is no underlying XML document. - * <p/> - * XML documents cannot be created per se -- they are a by-product of the StructuredEditor - * XML parser. - * - * @return The current value of getXmlDocument(). - */ - @Override - public Node createXmlNode() { - if (getXmlDocument() == null) { - // By design, a document node cannot be created, it is owned by the XML parser. - // By "design" this should never happen since the XML parser always creates an XML - // document container, even for an empty file. - throw new UnsupportedOperationException("Documents cannot be created"); //$NON-NLS-1$ - } - return getXmlDocument(); - } - - /** - * This method throws an exception and does not even try to delete the XML document. - * <p/> - * XML documents cannot be deleted per se -- they are a by-product of the StructuredEditor - * XML parser. - * - * @return The removed node or null if it didn't exist in the firtst place. - */ - @Override - public Node deleteXmlNode() { - // DEBUG. Change to log warning. - throw new UnsupportedOperationException("Documents cannot be deleted"); //$NON-NLS-1$ - } -} - diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java deleted file mode 100644 index 3728886..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiElementNode.java +++ /dev/null @@ -1,1500 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.layout.descriptors.CustomViewDescriptorService; -import com.android.ide.eclipse.editors.layout.descriptors.LayoutDescriptors; -import com.android.ide.eclipse.editors.manifest.descriptors.AndroidManifestDescriptors; -import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; -import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener.UiUpdateState; -import com.android.ide.eclipse.editors.xml.descriptors.XmlDescriptors; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.views.properties.IPropertyDescriptor; -import org.eclipse.ui.views.properties.IPropertySource; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.Text; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -/** - * Represents an XML node that can be modified by the user interface in the XML editor. - * <p/> - * Each tree viewer used in the application page's parts needs to keep a model representing - * each underlying node in the tree. This interface represents the base type for such a node. - * <p/> - * Each node acts as an intermediary model between the actual XML model (the real data support) - * and the tree viewers or the corresponding page parts. - * <p/> - * Element nodes don't contain data per se. Their data is contained in their attributes - * as well as their children's attributes, see {@link UiAttributeNode}. - * <p/> - * The structure of a given {@link UiElementNode} is declared by a corresponding - * {@link ElementDescriptor}. - * <p/> - * The class implements {@link IPropertySource}, in order to fill the Eclipse property tab when - * an element is selected. The {@link AttributeDescriptor} are used property descriptors. - */ -public class UiElementNode implements IPropertySource { - - /** List of prefixes removed from android:id strings when creating short descriptions. */ - private static String[] ID_PREFIXES = { - "@android:id/", //$NON-NLS-1$ - "@+id/", "@id/", "@+", "@" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - - /** The element descriptor for the node. Always present, never null. */ - private ElementDescriptor mDescriptor; - /** The parent element node in the UI model. It is null for a root element or until - * the node is attached to its parent. */ - private UiElementNode mUiParent; - /** The {@link AndroidEditor} handling the UI hierarchy. This is defined only for the - * root node. All children have the value set to null and query their parent. */ - private AndroidEditor mEditor; - /** The XML {@link Document} model that is being mirror by the UI model. This is defined - * only for the root node. All children have the value set to null and query their parent. */ - private Document mXmlDocument; - /** The XML {@link Node} mirror by this UI node. This can be null for mandatory UI node which - * have no corresponding XML node or for new UI nodes before their XML node is set. */ - private Node mXmlNode; - /** The list of all UI children nodes. Can be empty but never null. There's one UI children - * node per existing XML children node. */ - private ArrayList<UiElementNode> mUiChildren; - /** The list of <em>all</em> UI attributes, as declared in the {@link ElementDescriptor}. - * The list is always defined and never null. Unlike the UiElementNode children list, this - * is always defined, even for attributes that do not exist in the XML model -- that's because - * "missing" attributes in the XML model simply mean a default value is used. Also note that - * the underlying collection is a map, so order is not respected. To get the desired attribute - * order, iterate through the {@link ElementDescriptor}'s attribute list. */ - private HashMap<AttributeDescriptor, UiAttributeNode> mUiAttributes; - private HashSet<UiAttributeNode> mUnknownUiAttributes; - /** A read-only view of the UI children node collection. */ - private List<UiElementNode> mReadOnlyUiChildren; - /** A read-only view of the UI attributes collection. */ - private Collection<UiAttributeNode> mReadOnlyUiAttributes; - /** A map of hidden attribute descriptors. Key is the XML name. */ - private Map<String, AttributeDescriptor> mCachedHiddenAttributes; - /** An optional list of {@link IUiUpdateListener}. Most element nodes will not have any - * listeners attached, so the list is only created on demand and can be null. */ - private ArrayList<IUiUpdateListener> mUiUpdateListeners; - /** Error Flag */ - private boolean mHasError; - /** Temporary data used by the editors. This data is not sync'ed with the XML */ - private Object mEditData; - - /** - * Creates a new {@link UiElementNode} described by a given {@link ElementDescriptor}. - * - * @param elementDescriptor The {@link ElementDescriptor} for the XML node. Cannot be null. - */ - public UiElementNode(ElementDescriptor elementDescriptor) { - mDescriptor = elementDescriptor; - clearContent(); - } - - /** - * Clears the {@link UiElementNode} by resetting the children list and - * the {@link UiAttributeNode}s list. - * Also resets the attached XML node, document, editor if any. - * <p/> - * The parent {@link UiElementNode} node is not reset so that it's position - * in the hierarchy be left intact, if any. - */ - /* package */ void clearContent() { - mXmlNode = null; - mXmlDocument = null; - mEditor = null; - clearAttributes(); - mReadOnlyUiChildren = null; - if (mUiChildren == null) { - mUiChildren = new ArrayList<UiElementNode>(); - } else { - // We can't remove mandatory nodes, we just clear them. - for (int i = mUiChildren.size() - 1; i >= 0; --i) { - removeUiChildAtIndex(i); - } - } - } - - /** - * Clears the internal list of attributes, the read-only cached version of it - * and the read-only cached hidden attribute list. - */ - private void clearAttributes() { - mUiAttributes = null; - mReadOnlyUiAttributes = null; - mCachedHiddenAttributes = null; - mUnknownUiAttributes = new HashSet<UiAttributeNode>(); - } - - /** - * Gets or creates the internal UiAttributes list. - * <p/> - * When the descriptor derives from ViewElementDescriptor, this list depends on the - * current UiParent node. - * - * @return A new set of {@link UiAttributeNode} that matches the expected - * attributes for this node. - */ - private HashMap<AttributeDescriptor, UiAttributeNode> getInternalUiAttributes() { - if (mUiAttributes == null) { - AttributeDescriptor[] attr_list = getAttributeDescriptors(); - mUiAttributes = new HashMap<AttributeDescriptor, UiAttributeNode>(attr_list.length); - for (AttributeDescriptor desc : attr_list) { - UiAttributeNode ui_node = desc.createUiNode(this); - if (ui_node != null) { // Some AttributeDescriptors do not have UI associated - mUiAttributes.put(desc, ui_node); - } - } - } - return mUiAttributes; - } - - /** - * Computes a short string describing the UI node suitable for tree views. - * Uses the element's attribute "android:name" if present, or the "android:label" one - * followed by the element's name. - * - * @return A short string describing the UI node suitable for tree views. - */ - public String getShortDescription() { - if (mXmlNode != null && mXmlNode instanceof Element && mXmlNode.hasAttributes()) { - - // Application and Manifest nodes have a special treatment: they are unique nodes - // so we don't bother trying to differentiate their strings and we fall back to - // just using the UI name below. - Element elem = (Element) mXmlNode; - - String attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, - AndroidManifestDescriptors.ANDROID_NAME_ATTR); - if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, - AndroidManifestDescriptors.ANDROID_LABEL_ATTR); - } - if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, - XmlDescriptors.PREF_KEY_ATTR); - } - if (attr == null || attr.length() == 0) { - attr = elem.getAttribute(ResourcesDescriptors.NAME_ATTR); - } - if (attr == null || attr.length() == 0) { - attr = elem.getAttributeNS(SdkConstants.NS_RESOURCES, - LayoutDescriptors.ID_ATTR); - - if (attr != null && attr.length() > 0) { - for (String prefix : ID_PREFIXES) { - if (attr.startsWith(prefix)) { - attr = attr.substring(prefix.length()); - break; - } - } - } - } - if (attr != null && attr.length() > 0) { - return String.format("%1$s (%2$s)", attr, mDescriptor.getUiName()); - } - } - - return String.format("%1$s", mDescriptor.getUiName()); - } - - /** - * Computes a "breadcrumb trail" description for this node. - * It will look something like "Manifest > Application > .myactivity (Activity) > Intent-Filter" - * - * @param include_root Whether to include the root (e.g. "Manifest") or not. Has no effect - * when called on the root node itself. - * @return The "breadcrumb trail" description for this node. - */ - public String getBreadcrumbTrailDescription(boolean include_root) { - StringBuilder sb = new StringBuilder(getShortDescription()); - - for (UiElementNode ui_node = getUiParent(); - ui_node != null; - ui_node = ui_node.getUiParent()) { - if (!include_root && ui_node.getUiParent() == null) { - break; - } - sb.insert(0, String.format("%1$s > ", ui_node.getShortDescription())); //$NON-NLS-1$ - } - - return sb.toString(); - } - - /** - * Sets the XML {@link Document}. - * <p/> - * The XML {@link Document} is initially null. The XML {@link Document} must be set only on the - * UI root element node (this method takes care of that.) - */ - public void setXmlDocument(Document xml_doc) { - if (mUiParent == null) { - mXmlDocument = xml_doc; - } else { - mUiParent.setXmlDocument(xml_doc); - } - } - - /** - * Returns the XML {@link Document}. - * <p/> - * The value is initially null until the UI node is attached to its UI parent -- the value - * of the document is then propagated. - * - * @return the XML {@link Document} or the parent's XML {@link Document} or null. - */ - public Document getXmlDocument() { - if (mXmlDocument != null) { - return mXmlDocument; - } else if (mUiParent != null) { - return mUiParent.getXmlDocument(); - } - return null; - } - - /** - * Returns the XML node associated with this UI node. - * <p/> - * Some {@link ElementDescriptor} are declared as being "mandatory". This means the - * corresponding UI node will exist even if there is no corresponding XML node. Such structure - * is created and enforced by the parent of the tree, not the element themselves. However - * such nodes will likely not have an XML node associated, so getXmlNode() can return null. - * - * @return The associated XML node. Can be null for mandatory nodes. - */ - public Node getXmlNode() { - return mXmlNode; - } - - /** - * Returns the {@link ElementDescriptor} for this node. This is never null. - * <p/> - * Do not use this to call getDescriptor().getAttributes(), instead call - * getAttributeDescriptors() which can be overriden by derived classes. - */ - public ElementDescriptor getDescriptor() { - return mDescriptor; - } - - /** - * Returns the {@link AttributeDescriptor} array for the descriptor of this node. - * <p/> - * Use this instead of getDescriptor().getAttributes() -- derived classes can override - * this to manipulate the attribute descriptor list depending on the current UI node. - */ - public AttributeDescriptor[] getAttributeDescriptors() { - return mDescriptor.getAttributes(); - } - - /** - * Returns the hidden {@link AttributeDescriptor} array for the descriptor of this node. - * This is a subset of the getAttributeDescriptors() list. - * <p/> - * Use this instead of getDescriptor().getHiddenAttributes() -- potentially derived classes - * could override this to manipulate the attribute descriptor list depending on the current - * UI node. There's no need for it right now so keep it private. - */ - private Map<String, AttributeDescriptor> getHiddenAttributeDescriptors() { - if (mCachedHiddenAttributes == null) { - mCachedHiddenAttributes = new HashMap<String, AttributeDescriptor>(); - for (AttributeDescriptor attr_desc : getAttributeDescriptors()) { - if (attr_desc instanceof XmlnsAttributeDescriptor) { - mCachedHiddenAttributes.put( - ((XmlnsAttributeDescriptor) attr_desc).getXmlNsName(), - attr_desc); - } - } - } - return mCachedHiddenAttributes; - } - - /** - * Sets the parent of this UiElementNode. - * <p/> - * The root node has no parent. - */ - protected void setUiParent(UiElementNode parent) { - mUiParent = parent; - // Invalidate the internal UiAttributes list, as it may depend on the actual UiParent. - clearAttributes(); - } - - /** - * @return The parent {@link UiElementNode} or null if this is the root node. - */ - public UiElementNode getUiParent() { - return mUiParent; - } - - /** - * Returns The root {@link UiElementNode}. - */ - public UiElementNode getUiRoot() { - UiElementNode root = this; - while (root.mUiParent != null) { - root = root.mUiParent; - } - - return root; - } - - /** - * Returns the previous UI sibling of this UI node. - * If the node does not have a previous sibling, returns null. - */ - public UiElementNode getUiPreviousSibling() { - if (mUiParent != null) { - List<UiElementNode> childlist = mUiParent.getUiChildren(); - if (childlist != null && childlist.size() > 1 && childlist.get(0) != this) { - int index = childlist.indexOf(this); - return index > 0 ? childlist.get(index - 1) : null; - } - } - return null; - } - - /** - * Returns the next UI sibling of this UI node. - * If the node does not have a next sibling, returns null. - */ - public UiElementNode getUiNextSibling() { - if (mUiParent != null) { - List<UiElementNode> childlist = mUiParent.getUiChildren(); - if (childlist != null) { - int size = childlist.size(); - if (size > 1 && childlist.get(size - 1) != this) { - int index = childlist.indexOf(this); - return index >= 0 && index < size - 1 ? childlist.get(index + 1) : null; - } - } - } - return null; - } - - /** - * Sets the {@link AndroidEditor} handling this {@link UiElementNode} hierarchy. - * <p/> - * The editor must always be set on the root node. This method takes care of that. - */ - public void setEditor(AndroidEditor editor) { - if (mUiParent == null) { - mEditor = editor; - } else { - mUiParent.setEditor(editor); - } - } - - /** - * Returns the {@link AndroidEditor} that embeds this {@link UiElementNode}. - * <p/> - * The value is initially null until the node is attached to its parent -- the value - * of the root node is then propagated. - * - * @return The embedding {@link AndroidEditor} or null. - */ - public AndroidEditor getEditor() { - return mUiParent == null ? mEditor : mUiParent.getEditor(); - } - - /** - * Returns the Android target data for the file being edited. - */ - public AndroidTargetData getAndroidTarget() { - return getEditor().getTargetData(); - } - - /** - * @return A read-only version of the children collection. - */ - public List<UiElementNode> getUiChildren() { - if (mReadOnlyUiChildren == null) { - mReadOnlyUiChildren = Collections.unmodifiableList(mUiChildren); - } - return mReadOnlyUiChildren; - } - - /** - * @return A read-only version of the attributes collection. - */ - public Collection<UiAttributeNode> getUiAttributes() { - if (mReadOnlyUiAttributes == null) { - mReadOnlyUiAttributes = Collections.unmodifiableCollection( - getInternalUiAttributes().values()); - } - return mReadOnlyUiAttributes; - } - - /** - * @return A read-only version of the unknown attributes collection. - */ - public Collection<UiAttributeNode> getUnknownUiAttributes() { - return Collections.unmodifiableCollection(mUnknownUiAttributes); - } - - /** - * Sets the error flag value. - * @param errorFlag the error flag - */ - public final void setHasError(boolean errorFlag) { - mHasError = errorFlag; - } - - /** - * Returns whether this node, its attributes, or one of the children nodes (and attributes) - * has errors. - */ - public final boolean hasError() { - if (mHasError) { - return true; - } - - // get the error value from the attributes. - Collection<UiAttributeNode> attributes = getInternalUiAttributes().values(); - for (UiAttributeNode attribute : attributes) { - if (attribute.hasError()) { - return true; - } - } - - // and now from the children. - for (UiElementNode child : mUiChildren) { - if (child.hasError()) { - return true; - } - } - - return false; - } - - /** - * Adds a new {@link IUiUpdateListener} to the internal update listener list. - */ - public void addUpdateListener(IUiUpdateListener listener) { - if (mUiUpdateListeners == null) { - mUiUpdateListeners = new ArrayList<IUiUpdateListener>(); - } - if (!mUiUpdateListeners.contains(listener)) { - mUiUpdateListeners.add(listener); - } - } - - /** - * Removes an existing {@link IUiUpdateListener} from the internal update listener list. - * Does nothing if the list is empty or the listener is not registered. - */ - public void removeUpdateListener(IUiUpdateListener listener) { - if (mUiUpdateListeners != null) { - mUiUpdateListeners.remove(listener); - } - } - - /** - * Finds a child node relative to this node using a path-like expression. - * F.ex. "node1/node2" would find a child "node1" that contains a child "node2" and - * returns the latter. If there are multiple nodes with the same name at the same - * level, always uses the first one found. - * - * @param path The path like expression to select a child node. - * @return The ui node found or null. - */ - public UiElementNode findUiChildNode(String path) { - String[] items = path.split("/"); //$NON-NLS-1$ - UiElementNode ui_node = this; - for (String item : items) { - boolean next_segment = false; - for (UiElementNode c : ui_node.mUiChildren) { - if (c.getDescriptor().getXmlName().equals(item)) { - ui_node = c; - next_segment = true; - break; - } - } - if (!next_segment) { - return null; - } - } - return ui_node; - } - - /** - * Finds an {@link UiElementNode} which contains the give XML {@link Node}. - * Looks recursively in all children UI nodes. - * - * @param xmlNode The XML node to look for. - * @return The {@link UiElementNode} that contains xmlNode or null if not found, - */ - public UiElementNode findXmlNode(Node xmlNode) { - if (xmlNode == null) { - return null; - } - if (getXmlNode() == xmlNode) { - return this; - } - - for (UiElementNode uiChild : mUiChildren) { - UiElementNode found = uiChild.findXmlNode(xmlNode); - if (found != null) { - return found; - } - } - - return null; - } - - /** - * Returns the {@link UiAttributeNode} matching this attribute descriptor or - * null if not found. - * - * @param attr_desc The {@link AttributeDescriptor} to match. - * @return the {@link UiAttributeNode} matching this attribute descriptor or null - * if not found. - */ - public UiAttributeNode findUiAttribute(AttributeDescriptor attr_desc) { - return getInternalUiAttributes().get(attr_desc); - } - - /** - * Populate this element node with all values from the given XML node. - * - * This fails if the given XML node has a different element name -- it won't change the - * type of this ui node. - * - * This method can be both used for populating values the first time and updating values - * after the XML model changed. - * - * @param xml_node The XML node to mirror - * @return Returns true if the XML structure has changed (nodes added, removed or replaced) - */ - public boolean loadFromXmlNode(Node xml_node) { - boolean structure_changed = (mXmlNode != xml_node); - mXmlNode = xml_node; - if (xml_node != null) { - updateAttributeList(xml_node); - structure_changed |= updateElementList(xml_node); - invokeUiUpdateListeners(structure_changed ? UiUpdateState.CHILDREN_CHANGED - : UiUpdateState.ATTR_UPDATED); - } - return structure_changed; - } - - /** - * Clears the UI node and reload it from the given XML node. - * <p/> - * This works by clearing all references to any previous XML or UI nodes and - * then reloads the XML document from scratch. The editor reference is kept. - * <p/> - * This is used in the special case where the ElementDescriptor structure has changed. - * Rather than try to diff inflated UI nodes (as loadFromXmlNode does), we don't bother - * and reload everything. This is not subtle and should be used very rarely. - * - * @param xml_node The XML node or document to reload. Can be null. - */ - public void reloadFromXmlNode(Node xml_node) { - // The editor needs to be preserved, it is not affected by an XML change. - AndroidEditor editor = getEditor(); - clearContent(); - setEditor(editor); - if (xml_node != null) { - setXmlDocument(xml_node.getOwnerDocument()); - } - // This will reload all the XML and recreate the UI structure from scratch. - loadFromXmlNode(xml_node); - } - - /** - * Called by attributes when they want to commit their value - * to an XML node. - * <p/> - * For mandatory nodes, this makes sure the underlying XML element node - * exists in the model. If not, it is created and assigned as the underlying - * XML node. - * </br> - * For non-mandatory nodes, simply return the underlying XML node, which - * must always exists. - * - * @return The XML node matching this {@link UiElementNode} or null. - */ - public Node prepareCommit() { - if (getDescriptor().isMandatory()) { - createXmlNode(); - // The new XML node has been created. - // We don't need to refresh using loadFromXmlNode() since there are - // no attributes or elements that need to be loading into this node. - } - return getXmlNode(); - } - - /** - * Commits the attributes (all internal, inherited from UI parent & unknown attributes). - * This is called by the UI when the embedding part needs to be committed. - */ - public void commit() { - for (UiAttributeNode ui_attr : getInternalUiAttributes().values()) { - ui_attr.commit(); - } - - for (UiAttributeNode ui_attr : mUnknownUiAttributes) { - ui_attr.commit(); - } - } - - /** - * Returns true if the part has been modified with respect to the data - * loaded from the model. - */ - public boolean isDirty() { - for (UiAttributeNode ui_attr : getInternalUiAttributes().values()) { - if (ui_attr.isDirty()) { - return true; - } - } - - for (UiAttributeNode ui_attr : mUnknownUiAttributes) { - if (ui_attr.isDirty()) { - return true; - } - } - - return false; - } - - /** - * Creates the underlying XML element node for this UI node if it doesn't already - * exists. - * - * @return The new value of getXmlNode() (can be null if creation failed) - */ - public Node createXmlNode() { - if (mXmlNode != null) { - return null; - } - Node parentXmlNode = null; - if (mUiParent != null) { - parentXmlNode = mUiParent.prepareCommit(); - if (parentXmlNode == null) { - // The parent failed to create its own backing XML node. Abort. - // No need to throw an exception, the parent will most likely - // have done so itself. - return null; - } - } - - String element_name = getDescriptor().getXmlName(); - Document doc = getXmlDocument(); - - // We *must* have a root node. If not, we need to abort. - if (doc == null) { - throw new RuntimeException( - String.format("Missing XML document for %1$s XML node.", element_name)); - } - - // If we get here and parent_xml_node is null, the node is to be created - // as the root node of the document (which can't be null, cf check above). - if (parentXmlNode == null) { - parentXmlNode = doc; - } - - mXmlNode = doc.createElement(element_name); - - Node xmlNextSibling = null; - - UiElementNode uiNextSibling = getUiNextSibling(); - if (uiNextSibling != null) { - xmlNextSibling = uiNextSibling.getXmlNode(); - } - - parentXmlNode.insertBefore(mXmlNode, xmlNextSibling); - - // Insert a separator after the tag, to make it easier to read - Text sep = doc.createTextNode("\n"); - parentXmlNode.appendChild(sep); - - // Set all initial attributes in the XML node if they are not empty. - // Iterate on the descriptor list to get the desired order and then use the - // internal values, if any. - for (AttributeDescriptor attr_desc : getAttributeDescriptors()) { - if (attr_desc instanceof XmlnsAttributeDescriptor) { - XmlnsAttributeDescriptor desc = (XmlnsAttributeDescriptor) attr_desc; - Attr attr = doc.createAttributeNS(XmlnsAttributeDescriptor.XMLNS_URI, - desc.getXmlNsName()); - attr.setValue(desc.getValue()); - attr.setPrefix(desc.getXmlNsPrefix()); - mXmlNode.getAttributes().setNamedItemNS(attr); - } else { - UiAttributeNode ui_attr = getInternalUiAttributes().get(attr_desc); - commitAttributeToXml(ui_attr, ui_attr.getCurrentValue()); - } - } - - invokeUiUpdateListeners(UiUpdateState.CREATED); - return mXmlNode; - } - - /** - * Removes the XML node corresponding to this UI node if it exists - * and also removes all mirrored information in this UI node (i.e. children, attributes) - * - * @return The removed node or null if it didn't exist in the firtst place. - */ - public Node deleteXmlNode() { - if (mXmlNode == null) { - return null; - } - - // First clear the internals of the node and *then* actually deletes the XML - // node (because doing so will generate an update even and this node may be - // revisited via loadFromXmlNode). - Node old_xml_node = mXmlNode; - clearContent(); - - Node xml_parent = old_xml_node.getParentNode(); - if (xml_parent == null) { - xml_parent = getXmlDocument(); - } - old_xml_node = xml_parent.removeChild(old_xml_node); - - invokeUiUpdateListeners(UiUpdateState.DELETED); - return old_xml_node; - } - - /** - * Updates the element list for this UiElementNode. - * At the end, the list of children UiElementNode here will match the one from the - * provided XML {@link Node}: - * <ul> - * <li> Walk both the current ui children list and the xml children list at the same time. - * <li> If we have a new xml child but already reached the end of the ui child list, add the - * new xml node. - * <li> Otherwise, check if the xml node is referenced later in the ui child list and if so, - * move it here. It means the XML child list has been reordered. - * <li> Otherwise, this is a new XML node that we add in the middle of the ui child list. - * <li> At the end, we may have finished walking the xml child list but still have remaining - * ui children, simply delete them as they matching trailing xml nodes that have been - * removed unless they are mandatory ui nodes. - * </ul> - * Note that only the first case is used when populating the ui list the first time. - * - * @param xml_node The XML node to mirror - * @return True when the XML structure has changed. - */ - protected boolean updateElementList(Node xml_node) { - boolean structure_changed = false; - int ui_index = 0; - Node xml_child = xml_node.getFirstChild(); - while (xml_child != null) { - if (xml_child.getNodeType() == Node.ELEMENT_NODE) { - String element_name = xml_child.getNodeName(); - UiElementNode ui_node = null; - if (mUiChildren.size() <= ui_index) { - // A new node is being added at the end of the list - ElementDescriptor desc = mDescriptor.findChildrenDescriptor(element_name, - false /* recursive */); - if (desc == null) { - // Unknown node. Create a temporary descriptor for it. - // most important we want to auto-add unknown attributes to it. - AndroidEditor editor = getEditor(); - IEditorInput editorInput = editor.getEditorInput(); - if (editorInput instanceof IFileEditorInput) { - IFileEditorInput fileInput = (IFileEditorInput)editorInput; - desc = CustomViewDescriptorService.getInstance().getDescriptor( - fileInput.getFile().getProject(), element_name); - if (desc == null) { - desc = new ElementDescriptor(element_name); - } - } else { - desc = new ElementDescriptor(element_name); - // TODO associate a new "?" icon to this descriptor. - } - } - structure_changed = true; - ui_node = appendNewUiChild(desc); - ui_index++; - } else { - // A new node is being inserted or moved. - // Note: mandatory nodes can be created without an XML node in which case - // getXmlNode() is null. - UiElementNode ui_child; - int n = mUiChildren.size(); - for (int j = ui_index; j < n; j++) { - ui_child = mUiChildren.get(j); - if (ui_child.getXmlNode() != null && ui_child.getXmlNode() == xml_child) { - if (j > ui_index) { - // Found the same XML node at some later index, now move it here. - mUiChildren.remove(j); - mUiChildren.add(ui_index, ui_child); - structure_changed = true; - } - ui_node = ui_child; - ui_index++; - break; - } - } - - if (ui_node == null) { - // Look for an unused mandatory node with no XML node attached - // referencing the same XML element name - for (int j = ui_index; j < n; j++) { - ui_child = mUiChildren.get(j); - if (ui_child.getXmlNode() == null && - ui_child.getDescriptor().isMandatory() && - ui_child.getDescriptor().getXmlName().equals(element_name)) { - if (j > ui_index) { - // Found it, now move it here - mUiChildren.remove(j); - mUiChildren.add(ui_index, ui_child); - } - // assign the XML node to this empty mandatory element. - ui_child.mXmlNode = xml_child; - structure_changed = true; - ui_node = ui_child; - ui_index++; - } - } - } - - if (ui_node == null) { - // Inserting new node - ElementDescriptor desc = mDescriptor.findChildrenDescriptor(element_name, - false /* recursive */); - if (desc == null) { - // Unknown element. Simply ignore it. - AdtPlugin.log(IStatus.WARNING, - "AndroidManifest: Ignoring unknown '%s' XML element", //$NON-NLS-1$ - element_name); - } else { - structure_changed = true; - ui_node = insertNewUiChild(ui_index, desc); - ui_index++; - } - } - } - if (ui_node != null) { - // If we touched an UI Node, even an existing one, refresh its content. - // For new nodes, this will populate them recursively. - structure_changed |= ui_node.loadFromXmlNode(xml_child); - } - } - xml_child = xml_child.getNextSibling(); - } - - // There might be extra UI nodes at the end if the XML node list got shorter. - for (int index = mUiChildren.size() - 1; index >= ui_index; --index) { - structure_changed |= removeUiChildAtIndex(index); - } - - return structure_changed; - } - - /** - * Internal helper to remove an UI child node given by its index in the - * internal child list. - * - * Also invokes the update listener on the node to be deleted. - * - * @param ui_index The index of the UI child to remove, range 0 .. mUiChildren.size()-1 - * @return True if the structure has changed - * @throws IndexOutOfBoundsException if index is out of mUiChildren's bounds. Of course you - * know that could never happen unless the computer is on fire or something. - */ - private boolean removeUiChildAtIndex(int ui_index) { - UiElementNode ui_node = mUiChildren.get(ui_index); - invokeUiUpdateListeners(UiUpdateState.DELETED); - if (ui_node.getDescriptor().isMandatory()) { - // We can't remove a mandatory node, we just clear its content. - - // A mandatory node with no XML means it doesn't really exist, so it can't be - // deleted. - boolean xml_exists = (ui_node.getXmlNode() != null); - - ui_node.clearContent(); - return xml_exists; - } else { - mUiChildren.remove(ui_index); - return true; - } - } - - /** - * Creates a new {@link UiElementNode} from the given {@link ElementDescriptor} - * and appends it to the end of the element children list. - * - * @param descriptor The {@link ElementDescriptor} that knows how to create the UI node. - * @return The new UI node that has been appended - */ - public UiElementNode appendNewUiChild(ElementDescriptor descriptor) { - UiElementNode ui_node; - ui_node = descriptor.createUiNode(); - mUiChildren.add(ui_node); - ui_node.setUiParent(this); - ui_node.invokeUiUpdateListeners(UiUpdateState.CREATED); - return ui_node; - } - - /** - * Creates a new {@link UiElementNode} from the given {@link ElementDescriptor} - * and inserts it in the element children list at the specified position. - * - * @param index The position where to insert in the element children list. - * @param descriptor The {@link ElementDescriptor} that knows how to create the UI node. - * @return The new UI node. - */ - public UiElementNode insertNewUiChild(int index, ElementDescriptor descriptor) { - UiElementNode ui_node; - ui_node = descriptor.createUiNode(); - mUiChildren.add(index, ui_node); - ui_node.setUiParent(this); - ui_node.invokeUiUpdateListeners(UiUpdateState.CREATED); - return ui_node; - } - - /** - * Updates the {@link UiAttributeNode} list for this {@link UiElementNode}. - * <p/> - * For a given {@link UiElementNode}, the attribute list always exists in - * full and is totally independent of whether the XML model actually - * has the corresponding attributes. - * <p/> - * For each attribute declared in this {@link UiElementNode}, get - * the corresponding XML attribute. It may not exist, in which case the - * value will be null. We don't really know if a value has changed, so - * the updateValue() is called on the UI sattribute in all cases. - * - * @param xmlNode The XML node to mirror - */ - protected void updateAttributeList(Node xmlNode) { - NamedNodeMap xmlAttrMap = xmlNode.getAttributes(); - HashSet<Node> visited = new HashSet<Node>(); - - // For all known (i.e. expected) UI attributes, find an existing XML attribute of - // same (uri, local name) and update the internal Ui attribute value. - for (UiAttributeNode uiAttr : getInternalUiAttributes().values()) { - AttributeDescriptor desc = uiAttr.getDescriptor(); - if (!(desc instanceof SeparatorAttributeDescriptor)) { - Node xmlAttr = xmlAttrMap == null ? null : - xmlAttrMap.getNamedItemNS(desc.getNamespaceUri(), desc.getXmlLocalName()); - uiAttr.updateValue(xmlAttr); - visited.add(xmlAttr); - } - } - - // Clone the current list of unknown attributes. We'll then remove from this list when - // we still attributes which are still unknown. What will be left are the old unknown - // attributes that have been deleted in the current XML attribute list. - @SuppressWarnings("unchecked") //$NON-NLS-1$ - HashSet<UiAttributeNode> deleted = (HashSet<UiAttributeNode>) mUnknownUiAttributes.clone(); - - // We need to ignore hidden attributes. - Map<String, AttributeDescriptor> hiddenAttrDesc = getHiddenAttributeDescriptors(); - - // Traverse the actual XML attribute list to find unknown attributes - if (xmlAttrMap != null) { - for (int i = 0; i < xmlAttrMap.getLength(); i++) { - Node xmlAttr = xmlAttrMap.item(i); - // Ignore attributes which have actual descriptors - if (visited.contains(xmlAttr)) { - continue; - } - - String xmlFullName = xmlAttr.getNodeName(); - - // Ignore attributes which are hidden (based on the prefix:localName key) - if (hiddenAttrDesc.containsKey(xmlFullName)) { - continue; - } - - String xmlAttrLocalName = xmlAttr.getLocalName(); - String xmlNsUri = xmlAttr.getNamespaceURI(); - - UiAttributeNode uiAttr = null; - for (UiAttributeNode a : mUnknownUiAttributes) { - String aLocalName = a.getDescriptor().getXmlLocalName(); - String aNsUri = a.getDescriptor().getNamespaceUri(); - if (aLocalName.equals(xmlAttrLocalName) && - (aNsUri == xmlNsUri || (aNsUri != null && aNsUri.equals(xmlNsUri)))) { - // This attribute is still present in the unknown list - uiAttr = a; - // It has not been deleted - deleted.remove(a); - break; - } - } - if (uiAttr == null) { - // Create a new unknown attribute - TextAttributeDescriptor desc = new TextAttributeDescriptor( - xmlAttrLocalName, // xml name - xmlFullName, // ui name - xmlNsUri, // NS uri - "Unknown XML attribute"); // tooltip, translatable - uiAttr = desc.createUiNode(this); - mUnknownUiAttributes.add(uiAttr); - } - - uiAttr.updateValue(xmlAttr); - } - - // Remove from the internal list unknown attributes that have been deleted from the xml - for (UiAttributeNode a : deleted) { - mUnknownUiAttributes.remove(a); - } - } - } - - /** - * Invoke all registered {@link IUiUpdateListener} listening on this UI updates for this node. - */ - protected void invokeUiUpdateListeners(UiUpdateState state) { - if (mUiUpdateListeners != null) { - for (IUiUpdateListener listener : mUiUpdateListeners) { - try { - listener.uiElementNodeUpdated(this, state); - } catch (Exception e) { - // prevent a crashing listener from crashing the whole invocation chain - AdtPlugin.log(e, "UIElement Listener failed: %s, state=%s", //$NON-NLS-1$ - getBreadcrumbTrailDescription(true), - state.toString()); - } - } - } - } - - // --- for derived implementations only --- - - // TODO doc - protected void setXmlNode(Node xml_node) { - mXmlNode = xml_node; - } - - /** - * Sets the temporary data used by the editors. - * @param data the data. - */ - public void setEditData(Object data) { - mEditData = data; - } - - /** - * Returns the temporary data used by the editors for this object. - * @return the data, or <code>null</code> if none has been set. - */ - public Object getEditData() { - return mEditData; - } - - public void refreshUi() { - invokeUiUpdateListeners(UiUpdateState.ATTR_UPDATED); - } - - - // ------------- Helpers - - /** - * Helper method to commit a single attribute value to XML. - * <p/> - * This method updates the XML regardless of the current XML value. - * Callers should check first if an update is needed. - * If the new value is empty, the XML attribute will be actually removed. - * <p/> - * Note that the caller MUST ensure that modifying the underlying XML model is - * safe and must take care of marking the model as dirty if necessary. - * - * @see AndroidEditor#editXmlModel(Runnable) - * - * @param uiAttr The attribute node to commit. Must be a child of this UiElementNode. - * @param newValue The new value to set. - * @return True if the XML attribute was modified or removed, false if nothing changed. - */ - public boolean commitAttributeToXml(UiAttributeNode uiAttr, String newValue) { - // Get (or create) the underlying XML element node that contains the attributes. - Node element = prepareCommit(); - if (element != null && uiAttr != null) { - String attrLocalName = uiAttr.getDescriptor().getXmlLocalName(); - String attrNsUri = uiAttr.getDescriptor().getNamespaceUri(); - - NamedNodeMap attrMap = element.getAttributes(); - if (newValue == null || newValue.length() == 0) { - // Remove attribute if it's empty - if (attrMap.getNamedItemNS(attrNsUri, attrLocalName) != null) { - attrMap.removeNamedItemNS(attrNsUri, attrLocalName); - return true; - } - } else { - // Add or replace an attribute - Document doc = element.getOwnerDocument(); - if (doc != null) { - Attr attr = doc.createAttributeNS(attrNsUri, attrLocalName); - attr.setValue(newValue); - attr.setPrefix(lookupNamespacePrefix(element, attrNsUri)); - attrMap.setNamedItemNS(attr); - return true; - } - } - } - return false; - } - - /** - * Helper method to commit all dirty attributes values to XML. - * <p/> - * This method is useful if {@link #setAttributeValue(String, String, boolean)} has been - * called more than once and all the attributes marked as dirty must be commited to the - * XML. It calls {@link #commitAttributeToXml(UiAttributeNode, String)} on each dirty - * attribute. - * <p/> - * Note that the caller MUST ensure that modifying the underlying XML model is - * safe and must take care of marking the model as dirty if necessary. - * - * @see AndroidEditor#editXmlModel(Runnable) - * - * @return True if one or more values were actually modified or removed, - * false if nothing changed. - */ - public boolean commitDirtyAttributesToXml() { - boolean result = false; - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - for (Entry<AttributeDescriptor, UiAttributeNode> entry : attributeMap.entrySet()) { - UiAttributeNode ui_attr = entry.getValue(); - if (ui_attr.isDirty()) { - result |= commitAttributeToXml(ui_attr, ui_attr.getCurrentValue()); - ui_attr.setDirty(false); - } - } - return result; - } - - /** - * Returns the namespace prefix matching the requested namespace URI. - * If no such declaration is found, returns the default "android" prefix. - * - * @param node The current node. Must not be null. - * @param nsUri The namespace URI of which the prefix is to be found, - * e.g. SdkConstants.NS_RESOURCES - * @return The first prefix declared or the default "android" prefix. - */ - private String lookupNamespacePrefix(Node node, String nsUri) { - // Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java - // The following code emulates this simple call: - // String prefix = node.lookupPrefix(SdkConstants.NS_RESOURCES); - - // if the requested URI is null, it denotes an attribute with no namespace. - if (nsUri == null) { - return null; - } - - // per XML specification, the "xmlns" URI is reserved - if (XmlnsAttributeDescriptor.XMLNS_URI.equals(nsUri)) { - return "xmlns"; //$NON-NLS-1$ - } - - HashSet<String> visited = new HashSet<String>(); - Document doc = node == null ? null : node.getOwnerDocument(); - - for (; node != null && node.getNodeType() == Node.ELEMENT_NODE; - node = node.getParentNode()) { - NamedNodeMap attrs = node.getAttributes(); - for (int n = attrs.getLength() - 1; n >= 0; --n) { - Node attr = attrs.item(n); - if ("xmlns".equals(attr.getPrefix())) { //$NON-NLS-1$ - String uri = attr.getNodeValue(); - String nsPrefix = attr.getLocalName(); - if (SdkConstants.NS_RESOURCES.equals(uri)) { - return nsPrefix; - } - visited.add(nsPrefix); - } - } - } - - // Use a sensible default prefix if we can't find one. - // We need to make sure the prefix is not one that was declared in the scope - // visited above. - String prefix = SdkConstants.NS_RESOURCES.equals(nsUri) ? "android" : "ns"; //$NON-NLS-1$ //$NON-NLS-2$ - String base = prefix; - for (int i = 1; visited.contains(prefix); i++) { - prefix = base + Integer.toString(i); - } - - // Also create & define this prefix/URI in the XML document as an attribute in the - // first element of the document. - if (doc != null) { - node = doc.getFirstChild(); - while (node != null && node.getNodeType() != Node.ELEMENT_NODE) { - node = node.getNextSibling(); - } - if (node != null) { - Attr attr = doc.createAttributeNS(XmlnsAttributeDescriptor.XMLNS_URI, prefix); - attr.setValue(nsUri); - attr.setPrefix("xmlns"); //$NON-NLS-1$ - node.getAttributes().setNamedItemNS(attr); - } - } - - return prefix; - } - - /** - * Utility method to internally set the value of a text attribute for the current - * UiElementNode. - * <p/> - * This method is a helper. It silently ignores the errors such as the requested - * attribute not being present in the element or attribute not being settable. - * It accepts inherited attributes (such as layout). - * <p/> - * This does not commit to the XML model. It does mark the attribute node as dirty. - * This is up to the caller. - * - * @see #commitAttributeToXml(UiAttributeNode, String) - * @see #commitDirtyAttributesToXml() - * - * @param attrXmlName The XML name of the attribute to modify - * @param value The new value for the attribute. If set to null, the attribute is removed. - * @param override True if the value must be set even if one already exists. - * @return The {@link UiAttributeNode} that has been modified or null. - */ - public UiAttributeNode setAttributeValue(String attrXmlName, String value, boolean override) { - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - if (value == null) { - value = ""; //$NON-NLS-1$ -- this removes an attribute - } - - for (Entry<AttributeDescriptor, UiAttributeNode> entry : attributeMap.entrySet()) { - AttributeDescriptor ui_desc = entry.getKey(); - if (ui_desc.getXmlLocalName().equals(attrXmlName)) { - UiAttributeNode ui_attr = entry.getValue(); - // Not all attributes are editable, ignore those which are not - if (ui_attr instanceof IUiSettableAttributeNode) { - String current = ui_attr.getCurrentValue(); - // Only update (and mark as dirty) if the attribute did not have any - // value or if the value was different. - if (override || current == null || !current.equals(value)) { - ((IUiSettableAttributeNode) ui_attr).setCurrentValue(value); - // mark the attribute as dirty since their internal content - // as been modified, but not the underlying XML model - ui_attr.setDirty(true); - return ui_attr; - } - } - break; - } - } - return null; - } - - /** - * Utility method to retrieve the internal value of an attribute. - * <p/> - * Note that this retrieves the *field* value if the attribute has some UI, and - * not the actual XML value. They may differ if the attribute is dirty. - * - * @param attrXmlName The XML name of the attribute to modify - * @return The current internal value for the attribute or null in case of error. - */ - public String getAttributeValue(String attrXmlName) { - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - for (Entry<AttributeDescriptor, UiAttributeNode> entry : attributeMap.entrySet()) { - AttributeDescriptor ui_desc = entry.getKey(); - if (ui_desc.getXmlLocalName().equals(attrXmlName)) { - UiAttributeNode ui_attr = entry.getValue(); - return ui_attr.getCurrentValue(); - } - } - return null; - } - - // ------ IPropertySource methods - - public Object getEditableValue() { - return null; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors() - * - * Returns the property descriptor for this node. Since the descriptors are not linked to the - * data, the AttributeDescriptor are used directly. - */ - public IPropertyDescriptor[] getPropertyDescriptors() { - List<IPropertyDescriptor> propDescs = new ArrayList<IPropertyDescriptor>(); - - // get the standard descriptors - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - Set<AttributeDescriptor> keys = attributeMap.keySet(); - - - // we only want the descriptor that do implement the IPropertyDescriptor interface. - for (AttributeDescriptor key : keys) { - if (key instanceof IPropertyDescriptor) { - propDescs.add((IPropertyDescriptor)key); - } - } - - // now get the descriptor from the unknown attributes - for (UiAttributeNode unknownNode : mUnknownUiAttributes) { - if (unknownNode.getDescriptor() instanceof IPropertyDescriptor) { - propDescs.add((IPropertyDescriptor)unknownNode.getDescriptor()); - } - } - - // TODO cache this maybe, as it's not going to change (except for unknown descriptors) - return propDescs.toArray(new IPropertyDescriptor[propDescs.size()]); - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(java.lang.Object) - * - * Returns the value of a given property. The id is the result of IPropertyDescriptor.getId(), - * which return the AttributeDescriptor itself. - */ - public Object getPropertyValue(Object id) { - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - UiAttributeNode attribute = attributeMap.get(id); - - if (attribute == null) { - // look for the id in the unknown attributes. - for (UiAttributeNode unknownAttr : mUnknownUiAttributes) { - if (id == unknownAttr.getDescriptor()) { - return unknownAttr; - } - } - } - - return attribute; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.views.properties.IPropertySource#isPropertySet(java.lang.Object) - * - * Returns whether the property is set. In our case this is if the string is non empty. - */ - public boolean isPropertySet(Object id) { - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - UiAttributeNode attribute = attributeMap.get(id); - - if (attribute != null) { - return attribute.getCurrentValue().length() > 0; - } - - // look for the id in the unknown attributes. - for (UiAttributeNode unknownAttr : mUnknownUiAttributes) { - if (id == unknownAttr.getDescriptor()) { - return unknownAttr.getCurrentValue().length() > 0; - } - } - - return false; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.views.properties.IPropertySource#resetPropertyValue(java.lang.Object) - * - * Reset the property to its default value. For now we simply empty it. - */ - public void resetPropertyValue(Object id) { - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - UiAttributeNode attribute = attributeMap.get(id); - if (attribute != null) { - // TODO: reset the value of the attribute - - return; - } - - // look for the id in the unknown attributes. - for (UiAttributeNode unknownAttr : mUnknownUiAttributes) { - if (id == unknownAttr.getDescriptor()) { - // TODO: reset the value of the attribute - - return; - } - } - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(java.lang.Object, java.lang.Object) - * - * Set the property value. id is the result of IPropertyDescriptor.getId(), which is the - * AttributeDescriptor itself. Value should be a String. - */ - public void setPropertyValue(Object id, Object value) { - HashMap<AttributeDescriptor, UiAttributeNode> attributeMap = getInternalUiAttributes(); - - UiAttributeNode attribute = attributeMap.get(id); - - if (attribute == null) { - // look for the id in the unknown attributes. - for (UiAttributeNode unknownAttr : mUnknownUiAttributes) { - if (id == unknownAttr.getDescriptor()) { - attribute = unknownAttr; - break; - } - } - } - - if (attribute != null) { - final UiAttributeNode fAttribute = attribute; - - // get the current value and compare it to the new value - String oldValue = fAttribute.getCurrentValue(); - final String newValue = (String)value; - - if (oldValue.equals(newValue)) { - return; - } - - AndroidEditor editor = getEditor(); - editor.editXmlModel(new Runnable() { - public void run() { - commitAttributeToXml(fAttribute, newValue); - } - }); - } - } - - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiFlagAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiFlagAttributeNode.java deleted file mode 100644 index ddcf0a0..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiFlagAttributeNode.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.uimodel; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.FlagAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.ui.SectionHelper; - -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.resource.FontDescriptor; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.dialogs.SelectionStatusDialog; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -/** - * Represents an XML attribute that is defined by a set of flag values, - * i.e. enum names separated by pipe (|) characters. - * - * Note: in Android resources, a "flag" is a list of fixed values where one or - * more values can be selected using an "or", e.g. "align='left|top'". - * By contrast, an "enum" is a list of fixed values of which only one can be - * selected at a given time, e.g. "gravity='right'". - * <p/> - * This class handles the "flag" case. - * The "enum" case is done using {@link UiListAttributeNode}. - */ -public class UiFlagAttributeNode extends UiTextAttributeNode { - - public UiFlagAttributeNode(FlagAttributeDescriptor attributeDescriptor, - UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public void createUiControl(Composite parent, IManagedForm managedForm) { - setManagedForm(managedForm); - FormToolkit toolkit = managedForm.getToolkit(); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - - Label label = toolkit.createLabel(parent, desc.getUiName()); - label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip())); - - Composite composite = toolkit.createComposite(parent); - composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); - GridLayout gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - composite.setLayout(gl); - // Fixes missing text borders under GTK... also requires adding a 1-pixel margin - // for the text field below - toolkit.paintBordersFor(composite); - - final Text text = toolkit.createText(composite, getCurrentValue()); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK - text.setLayoutData(gd); - final Button selectButton = toolkit.createButton(composite, "Select...", SWT.PUSH); - - setTextWidget(text); - - selectButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - - String currentText = getTextWidgetValue(); - - String result = showDialog(selectButton.getShell(), currentText); - - if (result != null) { - setTextWidgetValue(result); - } - } - }); - } - - /** - * Get the flag names, either from the initial names set in the attribute - * or by querying the framework resource parser. - */ - @Override - public String[] getPossibleValues() { - String attr_name = getDescriptor().getXmlLocalName(); - String element_name = getUiParent().getDescriptor().getXmlName(); - - String[] values = null; - - if (getDescriptor() instanceof FlagAttributeDescriptor && - ((FlagAttributeDescriptor) getDescriptor()).getNames() != null) { - // Get enum values from the descriptor - values = ((FlagAttributeDescriptor) getDescriptor()).getNames(); - } - - if (values == null) { - // or from the AndroidTargetData - UiElementNode uiNode = getUiParent(); - AndroidEditor editor = uiNode.getEditor(); - AndroidTargetData data = editor.getTargetData(); - if (data != null) { - values = data.getAttributeValues(element_name, attr_name); - } - } - - return values; - } - - /** - * Shows a dialog letting the user choose a set of enum, and returns a string - * containing the result. - */ - public String showDialog(Shell shell, String currentValue) { - FlagSelectionDialog dlg = new FlagSelectionDialog( - shell, currentValue.trim().split("\\s*\\|\\s*")); //$NON-NLS-1$ - dlg.open(); - Object[] result = dlg.getResult(); - if (result != null) { - StringBuilder buf = new StringBuilder(); - for (Object name : result) { - if (name instanceof String) { - if (buf.length() > 0) { - buf.append("|"); //$NON-NLS-1$ - } - buf.append(name); - } - } - - return buf.toString(); - } - - return null; - - } - - /** - * Displays a list of flag names with checkboxes. - */ - private class FlagSelectionDialog extends SelectionStatusDialog { - - private Set<String> mCurrentSet; - private Table mTable; - - public FlagSelectionDialog(Shell parentShell, String[] currentNames) { - super(parentShell); - - mCurrentSet = new HashSet<String>(); - for (String name : currentNames) { - if (name.length() > 0) { - mCurrentSet.add(name); - } - } - - int shellStyle = getShellStyle(); - setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); - } - - @Override - protected void computeResult() { - if (mTable != null) { - ArrayList<String> results = new ArrayList<String>(); - - for (TableItem item : mTable.getItems()) { - if (item.getChecked()) { - results.add((String)item.getData()); - } - } - - setResult(results); - } - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite composite= new Composite(parent, SWT.NONE); - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - composite.setLayout(new GridLayout(1, true)); - composite.setFont(parent.getFont()); - - Label label = new Label(composite, SWT.NONE); - label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - label.setText(String.format("Select the flag values for attribute %1$s:", - ((FlagAttributeDescriptor) getDescriptor()).getUiName())); - - mTable = new Table(composite, SWT.CHECK | SWT.BORDER); - GridData data = new GridData(); - // The 60,18 hints are the ones used by AbstractElementListSelectionDialog - data.widthHint = convertWidthInCharsToPixels(60); - data.heightHint = convertHeightInCharsToPixels(18); - data.grabExcessVerticalSpace = true; - data.grabExcessHorizontalSpace = true; - data.horizontalAlignment = GridData.FILL; - data.verticalAlignment = GridData.FILL; - mTable.setLayoutData(data); - - mTable.setHeaderVisible(false); - final TableColumn column = new TableColumn(mTable, SWT.NONE); - - // List all the expected flag names and check those which are currently used - String[] names = getPossibleValues(); - if (names != null) { - for (String name : names) { - TableItem item = new TableItem(mTable, SWT.NONE); - item.setText(name); - item.setData(name); - - boolean hasName = mCurrentSet.contains(name); - item.setChecked(hasName); - if (hasName) { - mCurrentSet.remove(name); - } - } - } - - // If there are unknown flag names currently used, display them at the end if the - // table already checked. - if (!mCurrentSet.isEmpty()) { - FontDescriptor fontDesc = JFaceResources.getDialogFontDescriptor(); - fontDesc = fontDesc.withStyle(SWT.ITALIC); - Font font = fontDesc.createFont(JFaceResources.getDialogFont().getDevice()); - - for (String name : mCurrentSet) { - TableItem item = new TableItem(mTable, SWT.NONE); - item.setText(String.format("%1$s (unknown flag)", name)); - item.setData(name); - item.setChecked(true); - item.setFont(font); - } - } - - // Add a listener that will resize the column to the full width of the table - // so that only one column appears in the table even if the dialog is resized. - ControlAdapter listener = new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Rectangle r = mTable.getClientArea(); - column.setWidth(r.width); - } - }; - - mTable.addControlListener(listener); - listener.controlResized(null /* event not used */); - - // Add a selection listener that will check/uncheck items when they are double-clicked - mTable.addSelectionListener(new SelectionAdapter() { - /** Default selection means double-click on "most" platforms */ - @Override - public void widgetDefaultSelected(SelectionEvent e) { - if (e.item instanceof TableItem) { - TableItem i = (TableItem) e.item; - i.setChecked(!i.getChecked()); - } - super.widgetDefaultSelected(e); - } - }); - - Dialog.applyDialogFont(composite); - setHelpAvailable(false); - - return composite; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java deleted file mode 100644 index c5c10aa..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiListAttributeNode.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.ListAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; - -/** - * Represents an XML attribute which has possible built-in values, and can be modified by - * an editable Combo box. - * <p/> - * See {@link UiTextAttributeNode} for more information. - */ -public class UiListAttributeNode extends UiAbstractTextAttributeNode { - - protected Combo mCombo; - - public UiListAttributeNode(ListAttributeDescriptor attributeDescriptor, - UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public final void createUiControl(final Composite parent, IManagedForm managedForm) { - FormToolkit toolkit = managedForm.getToolkit(); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - - Label label = toolkit.createLabel(parent, desc.getUiName()); - label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip())); - - int style = SWT.DROP_DOWN; - mCombo = new Combo(parent, style); - TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE); - twd.maxWidth = 100; - mCombo.setLayoutData(twd); - - fillCombo(); - - setTextWidgetValue(getCurrentValue()); - - mCombo.addModifyListener(new ModifyListener() { - /** - * Sent when the text is modified, whether by the user via manual - * input or programmatic input via setText(). - * <p/> - * Simply mark the attribute as dirty if it really changed. - * The container SectionPart will collect these flag and manage them. - */ - public void modifyText(ModifyEvent e) { - if (!isInInternalTextModification() && - !isDirty() && - mCombo != null && - getCurrentValue() != null && - !mCombo.getText().equals(getCurrentValue())) { - setDirty(true); - } - } - }); - - // Remove self-reference when the widget is disposed - mCombo.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - mCombo = null; - } - }); - } - - protected void fillCombo() { - String[] values = getPossibleValues(); - - if (values == null) { - AdtPlugin.log(IStatus.ERROR, - "FrameworkResourceManager did not provide values yet for %1$s", - getDescriptor().getXmlLocalName()); - } else { - for (String value : values) { - mCombo.add(value); - } - } - } - - /** - * Get the list values, either from the initial values set in the attribute - * or by querying the framework resource parser. - */ - @Override - public String[] getPossibleValues() { - AttributeDescriptor descriptor = getDescriptor(); - UiElementNode uiParent = getUiParent(); - - String attr_name = descriptor.getXmlLocalName(); - String element_name = uiParent.getDescriptor().getXmlName(); - - // FrameworkResourceManager expects a specific prefix for the attribute. - String prefix = ""; - if (SdkConstants.NS_RESOURCES.equals(descriptor.getNamespaceUri())) { - prefix = "android:"; //$NON-NLS-1$ - } else if (XmlnsAttributeDescriptor.XMLNS_URI.equals(descriptor.getNamespaceUri())) { - prefix = "xmlns:"; //$NON-NLS-1$ - } - attr_name = prefix + attr_name; - - String[] values = null; - - if (descriptor instanceof ListAttributeDescriptor && - ((ListAttributeDescriptor) descriptor).getValues() != null) { - // Get enum values from the descriptor - values = ((ListAttributeDescriptor) descriptor).getValues(); - } - - if (values == null) { - // or from the AndroidTargetData - UiElementNode uiNode = getUiParent(); - AndroidEditor editor = uiNode.getEditor(); - AndroidTargetData data = editor.getTargetData(); - if (data != null) { - // get the great-grand-parent descriptor. - - // the parent should always exist. - UiElementNode grandParentNode = uiParent.getUiParent(); - - String greatGrandParentNodeName = null; - if (grandParentNode != null) { - UiElementNode greatGrandParentNode = grandParentNode.getUiParent(); - if (greatGrandParentNode != null) { - greatGrandParentNodeName = - greatGrandParentNode.getDescriptor().getXmlName(); - } - } - - values = data.getAttributeValues(element_name, attr_name, greatGrandParentNodeName); - } - } - - return values; - } - - @Override - public String getTextWidgetValue() { - if (mCombo != null) { - return mCombo.getText(); - } - - return null; - } - - @Override - public final boolean isValid() { - return mCombo != null; - } - - @Override - public void setTextWidgetValue(String value) { - if (mCombo != null) { - mCombo.setText(value); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java deleted file mode 100644 index 1c1e1bd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; -import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.ide.eclipse.editors.wizards.ReferenceChooserDialog; -import com.android.ide.eclipse.editors.wizards.ResourceChooser; - -import org.eclipse.core.resources.IProject; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; - -/** - * Represents an XML attribute for a resource that can be modified using a simple text field or - * a dialog to choose an existing resource. - * <p/> - * It can be configured to represent any kind of resource, by providing the desired - * {@link ResourceType} in the constructor. - * <p/> - * See {@link UiTextAttributeNode} for more information. - */ -public class UiResourceAttributeNode extends UiTextAttributeNode { - - private ResourceType mType; - - public UiResourceAttributeNode(ResourceType type, - AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - - mType = type; - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public void createUiControl(final Composite parent, IManagedForm managedForm) { - setManagedForm(managedForm); - FormToolkit toolkit = managedForm.getToolkit(); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - - Label label = toolkit.createLabel(parent, desc.getUiName()); - label.setLayoutData(new TableWrapData(TableWrapData.LEFT, TableWrapData.MIDDLE)); - SectionHelper.addControlTooltip(label, DescriptorsUtils.formatTooltip(desc.getTooltip())); - - Composite composite = toolkit.createComposite(parent); - composite.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB, TableWrapData.MIDDLE)); - GridLayout gl = new GridLayout(2, false); - gl.marginHeight = gl.marginWidth = 0; - composite.setLayout(gl); - // Fixes missing text borders under GTK... also requires adding a 1-pixel margin - // for the text field below - toolkit.paintBordersFor(composite); - - final Text text = toolkit.createText(composite, getCurrentValue()); - GridData gd = new GridData(GridData.FILL_HORIZONTAL); - gd.horizontalIndent = 1; // Needed by the fixed composite borders under GTK - text.setLayoutData(gd); - Button browseButton = toolkit.createButton(composite, "Browse...", SWT.PUSH); - - setTextWidget(text); - - // TODO Add a validator using onAddModifyListener - - browseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - String result = showDialog(parent.getShell(), text.getText().trim()); - if (result != null) { - text.setText(result); - } - } - }); - } - - /** - * Shows a dialog letting the user choose a set of enum, and returns a string - * containing the result. - */ - public String showDialog(Shell shell, String currentValue) { - // we need to get the project of the file being edited. - UiElementNode uiNode = getUiParent(); - AndroidEditor editor = uiNode.getEditor(); - IProject project = editor.getProject(); - if (project != null) { - // get the resource repository for this project and the system resources. - IResourceRepository projectRepository = - ResourceManager.getInstance().getProjectResources(project); - - if (mType != null) { - // get the Target Data to get the system resources - AndroidTargetData data = editor.getTargetData(); - IResourceRepository systemRepository = data.getSystemResources(); - - // open a resource chooser dialog for specified resource type. - ResourceChooser dlg = new ResourceChooser(mType, - projectRepository, systemRepository, shell); - - dlg.setCurrentResource(currentValue); - - if (dlg.open() == Window.OK) { - return dlg.getCurrentResource(); - } - } else { - ReferenceChooserDialog dlg = new ReferenceChooserDialog(projectRepository, - shell); - - dlg.setCurrentResource(currentValue); - - if (dlg.open() == Window.OK) { - return dlg.getCurrentResource(); - } - } - } - - return null; - } - - @Override - public String[] getPossibleValues() { - // TODO: compute a list of existing resources for content assist completion - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiSeparatorAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiSeparatorAttributeNode.java deleted file mode 100644 index 192f752..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiSeparatorAttributeNode.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.uimodel; - -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.FormToolkit; -import org.eclipse.ui.forms.widgets.TableWrapData; -import org.eclipse.ui.forms.widgets.TableWrapLayout; -import org.w3c.dom.Node; - -/** - * {@link UiSeparatorAttributeNode} does not represent any real attribute. - * <p/> - * It is used to separate groups of attributes visually. - */ -public class UiSeparatorAttributeNode extends UiAttributeNode { - - /** Creates a new {@link UiAttributeNode} linked to a specific {@link AttributeDescriptor} */ - public UiSeparatorAttributeNode(SeparatorAttributeDescriptor attrDesc, - UiElementNode uiParent) { - super(attrDesc, uiParent); - } - - /** Returns the current value of the node. */ - @Override - public String getCurrentValue() { - // There is no value here. - return null; - } - - /** - * Sets whether the attribute is dirty and also notifies the editor some part's dirty - * flag as changed. - * <p/> - * Subclasses should set the to true as a result of user interaction with the widgets in - * the section and then should set to false when the commit() method completed. - */ - @Override - public void setDirty(boolean isDirty) { - // This is never dirty. - } - - /** - * Called once by the parent user interface to creates the necessary - * user interface to edit this attribute. - * <p/> - * This method can be called more than once in the life cycle of an UI node, - * typically when the UI is part of a master-detail tree, as pages are swapped. - * - * @param parent The composite where to create the user interface. - * @param managedForm The managed form owning this part. - */ - @Override - public void createUiControl(Composite parent, IManagedForm managedForm) { - FormToolkit toolkit = managedForm.getToolkit(); - Composite row = toolkit.createComposite(parent); - - TableWrapData twd = new TableWrapData(TableWrapData.FILL_GRAB); - if (parent.getLayout() instanceof TableWrapLayout) { - twd.colspan = ((TableWrapLayout) parent.getLayout()).numColumns; - } - row.setLayoutData(twd); - row.setLayout(new GridLayout(3, false /* equal width */)); - - Label sep = toolkit.createSeparator(row, SWT.HORIZONTAL); - GridData gd = new GridData(SWT.LEFT, SWT.CENTER, false, false); - gd.widthHint = 16; - sep.setLayoutData(gd); - - Label label = toolkit.createLabel(row, getDescriptor().getXmlLocalName()); - label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); - - sep = toolkit.createSeparator(row, SWT.HORIZONTAL); - sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - } - - /** No completion values for this UI attribute. */ - @Override - public String[] getPossibleValues() { - return null; - } - - /** - * Called when the XML is being loaded or has changed to - * update the value held by this user interface attribute node. - * <p/> - * The XML Node <em>may</em> be null, which denotes that the attribute is not - * specified in the XML model. In general, this means the "default" value of the - * attribute should be used. - * <p/> - * The caller doesn't really know if attributes have changed, - * so it will call this to refresh the attribute anyway. It's up to the - * UI implementation to minimize refreshes. - * - * @param xml_attribute_node - */ - @Override - public void updateValue(Node xml_attribute_node) { - // No value to update. - } - - /** - * Called by the user interface when the editor is saved or its state changed - * and the modified attributes must be committed (i.e. written) to the XML model. - * <p/> - * Important behaviors: - * <ul> - * <li>The caller *must* have called IStructuredModel.aboutToChangeModel before. - * The implemented methods must assume it is safe to modify the XML model. - * <li>On success, the implementation *must* call setDirty(false). - * <li>On failure, the implementation can fail with an exception, which - * is trapped and logged by the caller, or do nothing, whichever is more - * appropriate. - * </ul> - */ - @Override - public void commit() { - // No value to commit. - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiTextAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiTextAttributeNode.java deleted file mode 100644 index 4c53f4c..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiTextAttributeNode.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.ui.SectionHelper; - -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.widgets.TableWrapData; - -/** - * Represents an XML attribute in that can be modified using a simple text field - * in the XML editor's user interface. - * <p/> - * The XML attribute has no default value. When unset, the text field is blank. - * When updating the XML, if the field is empty, the attribute will be removed - * from the XML element. - * <p/> - * See {@link UiAttributeNode} for more information. - */ -public class UiTextAttributeNode extends UiAbstractTextAttributeNode { - - /** Text field */ - private Text mText; - /** The managed form, set only once createUiControl has been called. */ - private IManagedForm mManagedForm; - - public UiTextAttributeNode(AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /* (non-java doc) - * Creates a label widget and an associated text field. - * <p/> - * As most other parts of the android manifest editor, this assumes the - * parent uses a table layout with 2 columns. - */ - @Override - public void createUiControl(Composite parent, IManagedForm managedForm) { - setManagedForm(managedForm); - TextAttributeDescriptor desc = (TextAttributeDescriptor) getDescriptor(); - Text text = SectionHelper.createLabelAndText(parent, managedForm.getToolkit(), - desc.getUiName(), getCurrentValue(), - DescriptorsUtils.formatTooltip(desc.getTooltip())); - - setTextWidget(text); - } - - /** No completion values for this UI attribute. */ - @Override - public String[] getPossibleValues() { - return null; - } - - /** - * Sets the internal managed form. - * This is usually set by createUiControl. - */ - protected void setManagedForm(IManagedForm managedForm) { - mManagedForm = managedForm; - } - - /** - * @return The managed form, set only once createUiControl has been called. - */ - protected IManagedForm getManagedForm() { - return mManagedForm; - } - - /* (non-java doc) - * Returns if the attribute node is valid, and its UI has been created. - */ - @Override - public boolean isValid() { - return mText != null; - } - - @Override - public String getTextWidgetValue() { - if (mText != null) { - return mText.getText(); - } - - return null; - } - - @Override - public void setTextWidgetValue(String value) { - if (mText != null) { - mText.setText(value); - } - } - - /** - * Sets the Text widget object, and prepares it to handle modification and synchronization - * with the XML node. - * @param textWidget - */ - protected final void setTextWidget(Text textWidget) { - mText = textWidget; - - if (textWidget != null) { - // Sets the with hint for the text field. Derived classes can always override it. - // This helps the grid layout to resize correctly on smaller screen sizes. - Object data = textWidget.getLayoutData(); - if (data == null) { - } else if (data instanceof GridData) { - ((GridData)data).widthHint = AndroidEditor.TEXT_WIDTH_HINT; - } else if (data instanceof TableWrapData) { - ((TableWrapData)data).maxWidth = 100; - } - - mText.addModifyListener(new ModifyListener() { - /** - * Sent when the text is modified, whether by the user via manual - * input or programmatic input via setText(). - * <p/> - * Simply mark the attribute as dirty if it really changed. - * The container SectionPart will collect these flag and manage them. - */ - public void modifyText(ModifyEvent e) { - if (!isInInternalTextModification() && - !isDirty() && - mText != null && - getCurrentValue() != null && - !mText.getText().equals(getCurrentValue())) { - setDirty(true); - } - } - }); - - // Remove self-reference when the widget is disposed - mText.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent e) { - mText = null; - } - }); - } - - onAddValidators(mText); - } - - /** - * Called after the text widget as been created. - * <p/> - * Derived classes typically want to: - * <li> Create a new {@link ModifyListener} and attach it to the given {@link Text} widget. - * <li> In the modify listener, call getManagedForm().getMessageManager().addMessage() - * and getManagedForm().getMessageManager().removeMessage() as necessary. - * <li> Call removeMessage in a new text.addDisposeListener. - * <li> Call the validator once to setup the initial messages as needed. - * <p/> - * The base implementation does nothing. - * - * @param text The {@link Text} widget to validate. - */ - protected void onAddValidators(Text text) { - } - - /** - * Returns the text widget. - */ - protected final Text getTextWidget() { - return mText; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiTextValueNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiTextValueNode.java deleted file mode 100644 index 5c1db05..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiTextValueNode.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.uimodel; - -import com.android.ide.eclipse.editors.descriptors.TextValueDescriptor; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.Text; - -/** - * Represents an XML element value in that can be modified using a simple text field - * in the XML editor's user interface. - */ -public class UiTextValueNode extends UiTextAttributeNode { - - public UiTextValueNode(TextValueDescriptor attributeDescriptor, UiElementNode uiParent) { - super(attributeDescriptor, uiParent); - } - - /** - * Updates the current text field's value when the XML has changed. - * <p/> - * The caller doesn't really know if value of the element has changed, - * so it will call this to refresh the value anyway. The value - * is only set if it has changed. - * <p/> - * This also resets the "dirty" flag. - */ - @Override - public void updateValue(Node xml_attribute_node) { - setCurrentValue(DEFAULT_VALUE); - - // The argument xml_attribute_node is not used here. It should always be - // null since this is not an attribute. What we want is the "text value" of - // the parent element, which is actually the first text node of the element. - - UiElementNode parent = getUiParent(); - if (parent != null) { - Node xml_node = parent.getXmlNode(); - if (xml_node != null) { - for (Node xml_child = xml_node.getFirstChild(); - xml_child != null; - xml_child = xml_child.getNextSibling()) { - if (xml_child.getNodeType() == Node.TEXT_NODE) { - setCurrentValue(xml_child.getNodeValue()); - break; - } - } - } - } - - if (isValid() && !getTextWidgetValue().equals(getCurrentValue())) { - try { - setInInternalTextModification(true); - setTextWidgetValue(getCurrentValue()); - setDirty(false); - } finally { - setInInternalTextModification(false); - } - } - } - - /* (non-java doc) - * Called by the user interface when the editor is saved or its state changed - * and the modified "attributes" must be committed (i.e. written) to the XML model. - */ - @Override - public void commit() { - UiElementNode parent = getUiParent(); - if (parent != null && isValid() && isDirty()) { - // Get (or create) the underlying XML element node that contains the value. - Node element = parent.prepareCommit(); - if (element != null) { - String value = getTextWidgetValue(); - - // Try to find an existing text child to update. - boolean updated = false; - - for (Node xml_child = element.getFirstChild(); - xml_child != null; - xml_child = xml_child.getNextSibling()) { - if (xml_child.getNodeType() == Node.TEXT_NODE) { - xml_child.setNodeValue(value); - updated = true; - break; - } - } - - // If we didn't find a text child to update, we need to create one. - if (!updated) { - Document doc = element.getOwnerDocument(); - if (doc != null) { - Text text = doc.createTextNode(value); - element.appendChild(text); - } - } - - setCurrentValue(value); - } - } - setDirty(false); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java deleted file mode 100644 index 4a05b1e..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java +++ /dev/null @@ -1,1278 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.wizards; - -import com.android.ide.eclipse.editors.resources.configurations.CountryCodeQualifier; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.configurations.KeyboardStateQualifier; -import com.android.ide.eclipse.editors.resources.configurations.LanguageQualifier; -import com.android.ide.eclipse.editors.resources.configurations.NavigationMethodQualifier; -import com.android.ide.eclipse.editors.resources.configurations.NetworkCodeQualifier; -import com.android.ide.eclipse.editors.resources.configurations.PixelDensityQualifier; -import com.android.ide.eclipse.editors.resources.configurations.RegionQualifier; -import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; -import com.android.ide.eclipse.editors.resources.configurations.ScreenDimensionQualifier; -import com.android.ide.eclipse.editors.resources.configurations.ScreenOrientationQualifier; -import com.android.ide.eclipse.editors.resources.configurations.TextInputMethodQualifier; -import com.android.ide.eclipse.editors.resources.configurations.TouchScreenQualifier; -import com.android.ide.eclipse.editors.resources.configurations.KeyboardStateQualifier.KeyboardState; -import com.android.ide.eclipse.editors.resources.configurations.NavigationMethodQualifier.NavigationMethod; -import com.android.ide.eclipse.editors.resources.configurations.ScreenOrientationQualifier.ScreenOrientation; -import com.android.ide.eclipse.editors.resources.configurations.TextInputMethodQualifier.TextInputMethod; -import com.android.ide.eclipse.editors.resources.configurations.TouchScreenQualifier.TouchScreenType; -import com.android.ide.eclipse.editors.resources.manager.ResourceManager; - -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.StackLayout; -import org.eclipse.swt.events.ControlAdapter; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.FocusAdapter; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.events.VerifyEvent; -import org.eclipse.swt.events.VerifyListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; - -import java.util.HashMap; - -/** - * Custom UI widget to let user build a Folder configuration. - * <p/> - * To use this, instantiate somewhere in the UI and then: - * <ul> - * <li>Use {@link #setConfiguration(String)} or {@link #setConfiguration(FolderConfiguration)}. - * <li>Retrieve the configuration using {@link #getConfiguration(FolderConfiguration)}. - * </ul> - */ -public class ConfigurationSelector extends Composite { - - public static final int WIDTH_HINT = 600; - public static final int HEIGHT_HINT = 250; - - private Runnable mOnChangeListener; - - private TableViewer mFullTableViewer; - private TableViewer mSelectionTableViewer; - private Button mAddButton; - private Button mRemoveButton; - private StackLayout mStackLayout; - - private boolean mOnRefresh = false; - - private final FolderConfiguration mBaseConfiguration = new FolderConfiguration(); - private final FolderConfiguration mSelectedConfiguration = new FolderConfiguration(); - - private final HashMap<Class<? extends ResourceQualifier>, QualifierEditBase> mUiMap = - new HashMap<Class<? extends ResourceQualifier>, QualifierEditBase>(); - private Composite mQualifierEditParent; - - /** - * Basic of {@link VerifyListener} to only accept digits. - */ - private static class DigitVerifier implements VerifyListener { - public void verifyText(VerifyEvent e) { - // check for digit only. - for (int i = 0 ; i < e.text.length(); i++) { - char letter = e.text.charAt(i); - if (letter < '0' || letter > '9') { - e.doit = false; - return; - } - } - } - } - - /** - * Implementation of {@link VerifyListener} for Country Code qualifiers. - */ - public static class MobileCodeVerifier extends DigitVerifier { - @Override - public void verifyText(VerifyEvent e) { - super.verifyText(e); - - // basic tests passed? - if (e.doit) { - // check the max 3 digits. - if (e.text.length() - e.end + e.start + - ((Text)e.getSource()).getText().length() > 3) { - e.doit = false; - } - } - } - } - - /** - * Implementation of {@link VerifyListener} for the Language and Region qualifiers. - */ - public static class LanguageRegionVerifier implements VerifyListener { - public void verifyText(VerifyEvent e) { - // check for length - if (e.text.length() - e.end + e.start + ((Combo)e.getSource()).getText().length() > 2) { - e.doit = false; - return; - } - - // check for lower case only. - for (int i = 0 ; i < e.text.length(); i++) { - char letter = e.text.charAt(i); - if ((letter < 'a' || letter > 'z') && (letter < 'A' || letter > 'Z')) { - e.doit = false; - return; - } - } - } - } - - /** - * Implementation of {@link VerifyListener} for the Pixel Density qualifier. - */ - public static class DensityVerifier extends DigitVerifier { } - - /** - * Implementation of {@link VerifyListener} for the Screen Dimension qualifier. - */ - public static class DimensionVerifier extends DigitVerifier { } - - /** - * Enum for the state of the configuration being created. - */ - public enum ConfigurationState { - OK, INVALID_CONFIG, REGION_WITHOUT_LANGUAGE; - } - - public ConfigurationSelector(Composite parent) { - super(parent, SWT.NONE); - - mBaseConfiguration.createDefault(); - - GridLayout gl = new GridLayout(4, false); - gl.marginWidth = gl.marginHeight = 0; - setLayout(gl); - - // first column is the first table - final Table fullTable = new Table(this, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER); - fullTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - fullTable.setHeaderVisible(true); - fullTable.setLinesVisible(true); - - // create the column - final TableColumn fullTableColumn = new TableColumn(fullTable, SWT.LEFT); - // set the header - fullTableColumn.setText("Available Qualifiers"); - - fullTable.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Rectangle r = fullTable.getClientArea(); - fullTableColumn.setWidth(r.width); - } - }); - - mFullTableViewer = new TableViewer(fullTable); - mFullTableViewer.setContentProvider(new QualifierContentProvider()); - mFullTableViewer.setLabelProvider(new QualifierLabelProvider( - false /* showQualifierValue */)); - mFullTableViewer.setInput(mBaseConfiguration); - mFullTableViewer.addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection) { - IStructuredSelection structSelection = (IStructuredSelection)selection; - Object first = structSelection.getFirstElement(); - - if (first instanceof ResourceQualifier) { - mAddButton.setEnabled(true); - return; - } - } - - mAddButton.setEnabled(false); - } - }); - - // 2nd column is the left/right arrow button - Composite buttonComposite = new Composite(this, SWT.NONE); - gl = new GridLayout(1, false); - gl.marginWidth = gl.marginHeight = 0; - buttonComposite.setLayout(gl); - buttonComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - - new Composite(buttonComposite, SWT.NONE); - mAddButton = new Button(buttonComposite, SWT.BORDER | SWT.PUSH); - mAddButton.setText("->"); - mAddButton.setEnabled(false); - mAddButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - IStructuredSelection selection = - (IStructuredSelection)mFullTableViewer.getSelection(); - - Object first = selection.getFirstElement(); - if (first instanceof ResourceQualifier) { - ResourceQualifier qualifier = (ResourceQualifier)first; - - mBaseConfiguration.removeQualifier(qualifier); - mSelectedConfiguration.addQualifier(qualifier); - - mFullTableViewer.refresh(); - mSelectionTableViewer.refresh(); - mSelectionTableViewer.setSelection(new StructuredSelection(qualifier), true); - - onChange(false /* keepSelection */); - } - } - }); - - mRemoveButton = new Button(buttonComposite, SWT.BORDER | SWT.PUSH); - mRemoveButton.setText("<-"); - mRemoveButton.setEnabled(false); - mRemoveButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - IStructuredSelection selection = - (IStructuredSelection)mSelectionTableViewer.getSelection(); - - Object first = selection.getFirstElement(); - if (first instanceof ResourceQualifier) { - ResourceQualifier qualifier = (ResourceQualifier)first; - - mSelectedConfiguration.removeQualifier(qualifier); - mBaseConfiguration.addQualifier(qualifier); - - mFullTableViewer.refresh(); - mSelectionTableViewer.refresh(); - - onChange(false /* keepSelection */); - } - } - }); - - // 3rd column is the selected config table - final Table selectionTable = new Table(this, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER); - selectionTable.setLayoutData(new GridData(GridData.FILL_BOTH)); - selectionTable.setHeaderVisible(true); - selectionTable.setLinesVisible(true); - - // create the column - final TableColumn selectionTableColumn = new TableColumn(selectionTable, SWT.LEFT); - // set the header - selectionTableColumn.setText("Chosen Qualifiers"); - - selectionTable.addControlListener(new ControlAdapter() { - @Override - public void controlResized(ControlEvent e) { - Rectangle r = selectionTable.getClientArea(); - selectionTableColumn.setWidth(r.width); - } - }); - mSelectionTableViewer = new TableViewer(selectionTable); - mSelectionTableViewer.setContentProvider(new QualifierContentProvider()); - mSelectionTableViewer.setLabelProvider(new QualifierLabelProvider( - true /* showQualifierValue */)); - mSelectionTableViewer.setInput(mSelectedConfiguration); - mSelectionTableViewer.addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - // ignore selection changes during resfreshes in some cases. - if (mOnRefresh) { - return; - } - - ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection) { - IStructuredSelection structSelection = (IStructuredSelection)selection; - - if (structSelection.isEmpty() == false) { - Object first = structSelection.getFirstElement(); - - if (first instanceof ResourceQualifier) { - mRemoveButton.setEnabled(true); - - QualifierEditBase composite = mUiMap.get(first.getClass()); - - if (composite != null) { - composite.setQualifier((ResourceQualifier)first); - } - - mStackLayout.topControl = composite; - mQualifierEditParent.layout(); - - return; - } - } else { - mStackLayout.topControl = null; - mQualifierEditParent.layout(); - } - } - - mRemoveButton.setEnabled(false); - } - }); - - // 4th column is the detail of the selected qualifier - mQualifierEditParent = new Composite(this, SWT.NONE); - mQualifierEditParent.setLayout(mStackLayout = new StackLayout()); - mQualifierEditParent.setLayoutData(new GridData(GridData.FILL_VERTICAL)); - - // create the UI for all the qualifiers, and associate them to the ResourceQualifer class. - mUiMap.put(CountryCodeQualifier.class, new MCCEdit(mQualifierEditParent)); - mUiMap.put(NetworkCodeQualifier.class, new MNCEdit(mQualifierEditParent)); - mUiMap.put(LanguageQualifier.class, new LanguageEdit(mQualifierEditParent)); - mUiMap.put(RegionQualifier.class, new RegionEdit(mQualifierEditParent)); - mUiMap.put(ScreenOrientationQualifier.class, new OrientationEdit(mQualifierEditParent)); - mUiMap.put(PixelDensityQualifier.class, new PixelDensityEdit(mQualifierEditParent)); - mUiMap.put(TouchScreenQualifier.class, new TouchEdit(mQualifierEditParent)); - mUiMap.put(KeyboardStateQualifier.class, new KeyboardEdit(mQualifierEditParent)); - mUiMap.put(TextInputMethodQualifier.class, new TextInputEdit(mQualifierEditParent)); - mUiMap.put(NavigationMethodQualifier.class, new NavigationEdit(mQualifierEditParent)); - mUiMap.put(ScreenDimensionQualifier.class, new ScreenDimensionEdit(mQualifierEditParent)); - } - - /** - * Sets a listener to be notified when the configuration changes. - * @param listener A {@link Runnable} whose <code>run()</code> method is called when the - * configuration is changed. The method is called from the UI thread. - */ - public void setOnChangeListener(Runnable listener) { - mOnChangeListener = listener; - } - - /** - * Initialize the UI with a given {@link FolderConfiguration}. This must - * be called from the UI thread. - * @param config The configuration. - */ - public void setConfiguration(FolderConfiguration config) { - mSelectedConfiguration.set(config); - mSelectionTableViewer.refresh(); - - // create the base config, which is the default config minus the qualifiers - // in SelectedConfiguration - mBaseConfiguration.substract(mSelectedConfiguration); - mFullTableViewer.refresh(); - } - - /** - * Initialize the UI with the configuration represented by a resource folder name. - * This must be called from the UI thread. - * - * @param folderSegments the segments of the folder name, - * split using {@link FolderConfiguration#QUALIFIER_SEP}. - * @return true if success, or false if the folder name is not a valid name. - */ - public boolean setConfiguration(String[] folderSegments) { - FolderConfiguration config = ResourceManager.getInstance().getConfig(folderSegments); - - if (config == null) { - return false; - } - - setConfiguration(config); - - return true; - } - - /** - * Initialize the UI with the configuration represented by a resource folder name. - * This must be called from the UI thread. - * @param folderName the name of the folder. - * @return true if success, or false if the folder name is not a valid name. - */ - public boolean setConfiguration(String folderName) { - // split the name of the folder in segments. - String[] folderSegments = folderName.split(FolderConfiguration.QUALIFIER_SEP); - - return setConfiguration(folderSegments); - } - - /** - * Gets the configuration as setup by the widget. - * @param config the {@link FolderConfiguration} object to be filled with the information - * from the UI. - */ - public void getConfiguration(FolderConfiguration config) { - config.set(mSelectedConfiguration); - } - - /** - * Returns the state of the configuration being edited/created. - */ - public ConfigurationState getState() { - if (mSelectedConfiguration.getInvalidQualifier() != null) { - return ConfigurationState.INVALID_CONFIG; - } - - if (mSelectedConfiguration.checkRegion() == false) { - return ConfigurationState.REGION_WITHOUT_LANGUAGE; - } - - return ConfigurationState.OK; - } - - /** - * Returns the first invalid qualifier of the configuration being edited/created, - * or <code>null<code> if they are all valid (or if none exists). - * <p/>If {@link #getState()} return {@link ConfigurationState#INVALID_CONFIG} then this will - * not return <code>null</code>. - */ - public ResourceQualifier getInvalidQualifier() { - return mSelectedConfiguration.getInvalidQualifier(); - } - - /** - * Handle changes in the configuration. - * @param keepSelection if <code>true</code> attemps to avoid triggering selection change in - * {@link #mSelectedConfiguration}. - */ - private void onChange(boolean keepSelection) { - ISelection selection = null; - if (keepSelection) { - mOnRefresh = true; - selection = mSelectionTableViewer.getSelection(); - } - - mSelectionTableViewer.refresh(true); - - if (keepSelection) { - mSelectionTableViewer.setSelection(selection); - mOnRefresh = false; - } - - if (mOnChangeListener != null) { - mOnChangeListener.run(); - } - } - - /** - * Content provider around a {@link FolderConfiguration}. - */ - private static class QualifierContentProvider implements IStructuredContentProvider { - - private FolderConfiguration mInput; - - public QualifierContentProvider() { - } - - public void dispose() { - // pass - } - - public Object[] getElements(Object inputElement) { - return mInput.getQualifiers(); - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - mInput = null; - if (newInput instanceof FolderConfiguration) { - mInput = (FolderConfiguration)newInput; - } - } - } - - /** - * Label provider for {@link ResourceQualifier} objects. - */ - private static class QualifierLabelProvider implements ITableLabelProvider { - - private final boolean mShowQualifierValue; - - public QualifierLabelProvider(boolean showQualifierValue) { - mShowQualifierValue = showQualifierValue; - } - - public String getColumnText(Object element, int columnIndex) { - // only one column, so we can ignore columnIndex - if (element instanceof ResourceQualifier) { - if (mShowQualifierValue) { - String value = ((ResourceQualifier)element).getStringValue(); - if (value.length() == 0) { - return String.format("%1$s (?)", - ((ResourceQualifier)element).getShortName()); - } else { - return value; - } - - } else { - return ((ResourceQualifier)element).getShortName(); - } - } - - return null; - } - - public Image getColumnImage(Object element, int columnIndex) { - // only one column, so we can ignore columnIndex - if (element instanceof ResourceQualifier) { - return ((ResourceQualifier)element).getIcon(); - } - - return null; - } - - public void addListener(ILabelProviderListener listener) { - // pass - } - - public void dispose() { - // pass - } - - public boolean isLabelProperty(Object element, String property) { - // pass - return false; - } - - public void removeListener(ILabelProviderListener listener) { - // pass - } - } - - /** - * Base class for Edit widget for {@link ResourceQualifier}. - */ - private abstract static class QualifierEditBase extends Composite { - - public QualifierEditBase(Composite parent, String title) { - super(parent, SWT.NONE); - setLayout(new GridLayout(1, false)); - - new Label(this, SWT.NONE).setText(title); - } - - public abstract void setQualifier(ResourceQualifier qualifier); - } - - /** - * Edit widget for {@link CountryCodeQualifier}. - */ - private class MCCEdit extends QualifierEditBase { - - private Text mText; - - public MCCEdit(Composite parent) { - super(parent, CountryCodeQualifier.NAME); - - mText = new Text(this, SWT.BORDER); - mText.addVerifyListener(new MobileCodeVerifier()); - mText.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onTextChange(); - } - }); - - mText.addFocusListener(new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - onTextChange(); - } - }); - - new Label(this, SWT.NONE).setText("(3 digit code)"); - } - - private void onTextChange() { - String value = mText.getText(); - - if (value.length() == 0) { - // empty string, means a qualifier with no value. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier()); - } else { - try { - CountryCodeQualifier qualifier = CountryCodeQualifier.getQualifier( - CountryCodeQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mSelectedConfiguration.setCountryCodeQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong - // (for instance not exactly 3 digits). - mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier()); - } - } catch (NumberFormatException nfe) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - mSelectedConfiguration.setCountryCodeQualifier(new CountryCodeQualifier()); - } - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - CountryCodeQualifier q = (CountryCodeQualifier)qualifier; - - mText.setText(Integer.toString(q.getCode())); - } - } - - /** - * Edit widget for {@link NetworkCodeQualifier}. - */ - private class MNCEdit extends QualifierEditBase { - private Text mText; - - public MNCEdit(Composite parent) { - super(parent, NetworkCodeQualifier.NAME); - - mText = new Text(this, SWT.BORDER); - mText.addVerifyListener(new MobileCodeVerifier()); - mText.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onTextChange(); - } - }); - mText.addFocusListener(new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - onTextChange(); - } - }); - - new Label(this, SWT.NONE).setText("(1-3 digit code)"); - } - - private void onTextChange() { - String value = mText.getText(); - - if (value.length() == 0) { - // empty string, means a qualifier with no value. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier()); - } else { - try { - NetworkCodeQualifier qualifier = NetworkCodeQualifier.getQualifier( - NetworkCodeQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mSelectedConfiguration.setNetworkCodeQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong - // (for instance not exactly 3 digits). - mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier()); - } - } catch (NumberFormatException nfe) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - mSelectedConfiguration.setNetworkCodeQualifier(new NetworkCodeQualifier()); - } - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - NetworkCodeQualifier q = (NetworkCodeQualifier)qualifier; - - mText.setText(Integer.toString(q.getCode())); - } - } - - /** - * Edit widget for {@link LanguageQualifier}. - */ - private class LanguageEdit extends QualifierEditBase { - private Combo mLanguage; - - public LanguageEdit(Composite parent) { - super(parent, LanguageQualifier.NAME); - - mLanguage = new Combo(this, SWT.DROP_DOWN); - mLanguage.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mLanguage.addVerifyListener(new LanguageRegionVerifier()); - mLanguage.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onLanguageChange(); - } - public void widgetSelected(SelectionEvent e) { - onLanguageChange(); - } - }); - mLanguage.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onLanguageChange(); - } - }); - - new Label(this, SWT.NONE).setText("(2 letter code)"); - } - - private void onLanguageChange() { - // update the current config - String value = mLanguage.getText(); - - if (value.length() == 0) { - // empty string, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setLanguageQualifier(new LanguageQualifier()); - } else { - LanguageQualifier qualifier = null; - String segment = LanguageQualifier.getFolderSegment(value); - if (segment != null) { - qualifier = LanguageQualifier.getQualifier(segment); - } - - if (qualifier != null) { - mSelectedConfiguration.setLanguageQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - mSelectedConfiguration.setLanguageQualifier(new LanguageQualifier()); - } - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - LanguageQualifier q = (LanguageQualifier)qualifier; - - String value = q.getValue(); - if (value != null) { - mLanguage.setText(value); - } - } - } - - /** - * Edit widget for {@link RegionQualifier}. - */ - private class RegionEdit extends QualifierEditBase { - private Combo mRegion; - - public RegionEdit(Composite parent) { - super(parent, RegionQualifier.NAME); - - mRegion = new Combo(this, SWT.DROP_DOWN); - mRegion.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mRegion.addVerifyListener(new LanguageRegionVerifier()); - mRegion.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onRegionChange(); - } - public void widgetSelected(SelectionEvent e) { - onRegionChange(); - } - }); - mRegion.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onRegionChange(); - } - }); - - new Label(this, SWT.NONE).setText("(2 letter code)"); - } - - private void onRegionChange() { - // update the current config - String value = mRegion.getText(); - - if (value.length() == 0) { - // empty string, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setRegionQualifier(new RegionQualifier()); - } else { - RegionQualifier qualifier = null; - String segment = RegionQualifier.getFolderSegment(value); - if (segment != null) { - qualifier = RegionQualifier.getQualifier(segment); - } - - if (qualifier != null) { - mSelectedConfiguration.setRegionQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong (for instance a one letter string). - mSelectedConfiguration.setRegionQualifier(new RegionQualifier()); - } - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - RegionQualifier q = (RegionQualifier)qualifier; - - String value = q.getValue(); - if (value != null) { - mRegion.setText(q.getValue()); - } - } - } - - /** - * Edit widget for {@link ScreenOrientationQualifier}. - */ - private class OrientationEdit extends QualifierEditBase { - - private Combo mOrientation; - - public OrientationEdit(Composite parent) { - super(parent, ScreenOrientationQualifier.NAME); - - mOrientation = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); - ScreenOrientation[] soValues = ScreenOrientation.values(); - for (ScreenOrientation value : soValues) { - mOrientation.add(value.getDisplayValue()); - } - - mOrientation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mOrientation.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onOrientationChange(); - } - public void widgetSelected(SelectionEvent e) { - onOrientationChange(); - } - }); - } - - protected void onOrientationChange() { - // update the current config - int index = mOrientation.getSelectionIndex(); - - if (index != -1) { - mSelectedConfiguration.setScreenOrientationQualifier(new ScreenOrientationQualifier( - ScreenOrientation.getByIndex(index))); - } else { - // empty selection, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setScreenOrientationQualifier( - new ScreenOrientationQualifier()); - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - ScreenOrientationQualifier q = (ScreenOrientationQualifier)qualifier; - - ScreenOrientation value = q.getValue(); - if (value == null) { - mOrientation.clearSelection(); - } else { - mOrientation.select(ScreenOrientation.getIndex(value)); - } - } - } - - /** - * Edit widget for {@link PixelDensityQualifier}. - */ - private class PixelDensityEdit extends QualifierEditBase { - private Text mText; - - public PixelDensityEdit(Composite parent) { - super(parent, PixelDensityQualifier.NAME); - - mText = new Text(this, SWT.BORDER); - mText.addVerifyListener(new DensityVerifier()); - mText.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onTextChange(); - } - }); - mText.addFocusListener(new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - onTextChange(); - } - }); - } - - private void onTextChange() { - String value = mText.getText(); - - if (value.length() == 0) { - // empty string, means a qualifier with no value. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setPixelDensityQualifier(new PixelDensityQualifier()); - } else { - try { - PixelDensityQualifier qualifier = PixelDensityQualifier.getQualifier( - PixelDensityQualifier.getFolderSegment(Integer.parseInt(value))); - if (qualifier != null) { - mSelectedConfiguration.setPixelDensityQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong - // (for instance a one letter string). - // We do nothing in this case. - return; - } - } catch (NumberFormatException nfe) { - // Looks like the code is not a number. This should not happen since the text - // field has a VerifyListener that prevents it. - // We do nothing in this case. - return; - } - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - PixelDensityQualifier q = (PixelDensityQualifier)qualifier; - - mText.setText(Integer.toString(q.getValue())); - } - } - - /** - * Edit widget for {@link TouchScreenQualifier}. - */ - private class TouchEdit extends QualifierEditBase { - - private Combo mTouchScreen; - - public TouchEdit(Composite parent) { - super(parent, TouchScreenQualifier.NAME); - - mTouchScreen = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); - TouchScreenType[] tstValues = TouchScreenType.values(); - for (TouchScreenType value : tstValues) { - mTouchScreen.add(value.getDisplayValue()); - } - - mTouchScreen.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mTouchScreen.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onTouchChange(); - } - public void widgetSelected(SelectionEvent e) { - onTouchChange(); - } - }); - } - - protected void onTouchChange() { - // update the current config - int index = mTouchScreen.getSelectionIndex(); - - if (index != -1) { - mSelectedConfiguration.setTouchTypeQualifier(new TouchScreenQualifier( - TouchScreenType.getByIndex(index))); - } else { - // empty selection, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setTouchTypeQualifier(new TouchScreenQualifier()); - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - TouchScreenQualifier q = (TouchScreenQualifier)qualifier; - - TouchScreenType value = q.getValue(); - if (value == null) { - mTouchScreen.clearSelection(); - } else { - mTouchScreen.select(TouchScreenType.getIndex(value)); - } - } - } - - /** - * Edit widget for {@link KeyboardStateQualifier}. - */ - private class KeyboardEdit extends QualifierEditBase { - - private Combo mKeyboard; - - public KeyboardEdit(Composite parent) { - super(parent, KeyboardStateQualifier.NAME); - - mKeyboard = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); - KeyboardState[] ksValues = KeyboardState.values(); - for (KeyboardState value : ksValues) { - mKeyboard.add(value.getDisplayValue()); - } - - mKeyboard.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mKeyboard.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onKeyboardChange(); - } - public void widgetSelected(SelectionEvent e) { - onKeyboardChange(); - } - }); - } - - protected void onKeyboardChange() { - // update the current config - int index = mKeyboard.getSelectionIndex(); - - if (index != -1) { - mSelectedConfiguration.setKeyboardStateQualifier(new KeyboardStateQualifier( - KeyboardState.getByIndex(index))); - } else { - // empty selection, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setKeyboardStateQualifier( - new KeyboardStateQualifier()); - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - KeyboardStateQualifier q = (KeyboardStateQualifier)qualifier; - - KeyboardState value = q.getValue(); - if (value == null) { - mKeyboard.clearSelection(); - } else { - mKeyboard.select(KeyboardState.getIndex(value)); - } - } - } - - /** - * Edit widget for {@link TextInputMethodQualifier}. - */ - private class TextInputEdit extends QualifierEditBase { - - private Combo mTextInput; - - public TextInputEdit(Composite parent) { - super(parent, TextInputMethodQualifier.NAME); - - mTextInput = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); - TextInputMethod[] timValues = TextInputMethod.values(); - for (TextInputMethod value : timValues) { - mTextInput.add(value.getDisplayValue()); - } - - mTextInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mTextInput.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onTextInputChange(); - } - public void widgetSelected(SelectionEvent e) { - onTextInputChange(); - } - }); - } - - protected void onTextInputChange() { - // update the current config - int index = mTextInput.getSelectionIndex(); - - if (index != -1) { - mSelectedConfiguration.setTextInputMethodQualifier(new TextInputMethodQualifier( - TextInputMethod.getByIndex(index))); - } else { - // empty selection, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setTextInputMethodQualifier( - new TextInputMethodQualifier()); - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - TextInputMethodQualifier q = (TextInputMethodQualifier)qualifier; - - TextInputMethod value = q.getValue(); - if (value == null) { - mTextInput.clearSelection(); - } else { - mTextInput.select(TextInputMethod.getIndex(value)); - } - } - } - - /** - * Edit widget for {@link NavigationMethodQualifier}. - */ - private class NavigationEdit extends QualifierEditBase { - - private Combo mNavigation; - - public NavigationEdit(Composite parent) { - super(parent, NavigationMethodQualifier.NAME); - - mNavigation = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); - NavigationMethod[] nmValues = NavigationMethod.values(); - for (NavigationMethod value : nmValues) { - mNavigation.add(value.getDisplayValue()); - } - - mNavigation.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mNavigation.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - onNavigationChange(); - } - public void widgetSelected(SelectionEvent e) { - onNavigationChange(); - } - }); - } - - protected void onNavigationChange() { - // update the current config - int index = mNavigation.getSelectionIndex(); - - if (index != -1) { - mSelectedConfiguration.setNavigationMethodQualifier(new NavigationMethodQualifier( - NavigationMethod.getByIndex(index))); - } else { - // empty selection, means no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setNavigationMethodQualifier( - new NavigationMethodQualifier()); - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - NavigationMethodQualifier q = (NavigationMethodQualifier)qualifier; - - NavigationMethod value = q.getValue(); - if (value == null) { - mNavigation.clearSelection(); - } else { - mNavigation.select(NavigationMethod.getIndex(value)); - } - } - } - - /** - * Edit widget for {@link ScreenDimensionQualifier}. - */ - private class ScreenDimensionEdit extends QualifierEditBase { - - private Text mSize1; - private Text mSize2; - - public ScreenDimensionEdit(Composite parent) { - super(parent, ScreenDimensionQualifier.NAME); - - ModifyListener modifyListener = new ModifyListener() { - public void modifyText(ModifyEvent e) { - onSizeChange(); - } - }; - - FocusAdapter focusListener = new FocusAdapter() { - @Override - public void focusLost(FocusEvent e) { - onSizeChange(); - } - }; - - mSize1 = new Text(this, SWT.BORDER); - mSize1.addVerifyListener(new DimensionVerifier()); - mSize1.addModifyListener(modifyListener); - mSize1.addFocusListener(focusListener); - - mSize2 = new Text(this, SWT.BORDER); - mSize2.addVerifyListener(new DimensionVerifier()); - mSize2.addModifyListener(modifyListener); - mSize2.addFocusListener(focusListener); - } - - private void onSizeChange() { - // update the current config - String size1 = mSize1.getText(); - String size2 = mSize2.getText(); - - if (size1.length() == 0 || size2.length() == 0) { - // if one of the strings is empty, reset to no qualifier. - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setScreenDimensionQualifier(new ScreenDimensionQualifier()); - } else { - ScreenDimensionQualifier qualifier = ScreenDimensionQualifier.getQualifier(size1, - size2); - - if (qualifier != null) { - mSelectedConfiguration.setScreenDimensionQualifier(qualifier); - } else { - // Failure! Looks like the value is wrong, reset the qualifier - // Since the qualifier classes are immutable, and we don't want to - // remove the qualifier from the configuration, we create a new default one. - mSelectedConfiguration.setScreenDimensionQualifier( - new ScreenDimensionQualifier()); - } - } - - // notify of change - onChange(true /* keepSelection */); - } - - @Override - public void setQualifier(ResourceQualifier qualifier) { - ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier; - - mSize1.setText(Integer.toString(q.getValue1())); - mSize2.setText(Integer.toString(q.getValue2())); - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java deleted file mode 100644 index 4d17176..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.wizards; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.project.ProjectChooserHelper; -import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.menu.descriptors.MenuDescriptors; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; -import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; - -/** - * This is the single page of the {@link NewXmlFileWizard} which provides the ability to create - * skeleton XML resources files for Android projects. - * <p/> - * This page is used to select the project, the resource folder, resource type and file name. - */ -class NewXmlFileCreationPage extends WizardPage { - - /** - * Information on one type of resource that can be created (e.g. menu, pref, layout, etc.) - */ - static class TypeInfo { - private final String mUiName; - private final ResourceFolderType mResFolderType; - private final String mTooltip; - private final Object mRootSeed; - private Button mWidget; - private ArrayList<String> mRoots = new ArrayList<String>(); - private final String mXmlns; - private final String mDefaultAttrs; - private final String mDefaultRoot; - - public TypeInfo(String uiName, - String tooltip, - ResourceFolderType resFolderType, - Object rootSeed, - String defaultRoot, - String xmlns, - String defaultAttrs) { - mUiName = uiName; - mResFolderType = resFolderType; - mTooltip = tooltip; - mRootSeed = rootSeed; - mDefaultRoot = defaultRoot; - mXmlns = xmlns; - mDefaultAttrs = defaultAttrs; - } - - /** Returns the UI name for the resource type. Unique. Never null. */ - String getUiName() { - return mUiName; - } - - /** Returns the tooltip for the resource type. Can be null. */ - String getTooltip() { - return mTooltip; - } - - /** - * Returns the name of the {@link ResourceFolderType}. - * Never null but not necessarily unique, - * e.g. two types use {@link ResourceFolderType#XML}. - */ - String getResFolderName() { - return mResFolderType.getName(); - } - - /** - * Returns the matching {@link ResourceFolderType}. - * Never null but not necessarily unique, - * e.g. two types use {@link ResourceFolderType#XML}. - */ - ResourceFolderType getResFolderType() { - return mResFolderType; - } - - /** Sets the radio button associate with the resource type. Can be null. */ - void setWidget(Button widget) { - mWidget = widget; - } - - /** Returns the radio button associate with the resource type. Can be null. */ - Button getWidget() { - return mWidget; - } - - /** - * Returns the seed used to fill the root element values. - * The seed might be either a String, a String array, an {@link ElementDescriptor}, - * a {@link DocumentDescriptor} or null. - */ - Object getRootSeed() { - return mRootSeed; - } - - /** Returns the default root element that should be selected by default. Can be null. */ - String getDefaultRoot() { - return mDefaultRoot; - } - - /** - * Returns the list of all possible root elements for the resource type. - * This can be an empty ArrayList but not null. - * <p/> - * TODO: the root list SHOULD depend on the currently selected project, to include - * custom classes. - */ - ArrayList<String> getRoots() { - return mRoots; - } - - /** - * If the generated resource XML file requires an "android" XMLNS, this should be set - * to {@link SdkConstants#NS_RESOURCES}. When it is null, no XMLNS is generated. - */ - String getXmlns() { - return mXmlns; - } - - /** - * When not null, this represent extra attributes that must be specified in the - * root element of the generated XML file. When null, no extra attributes are inserted. - */ - String getDefaultAttrs() { - return mDefaultAttrs; - } - } - - /** - * TypeInfo, information for each "type" of file that can be created. - */ - private static final TypeInfo[] sTypes = { - new TypeInfo( - "Layout", // UI name - "An XML file that describes a screen layout.", // tooltip - ResourceFolderType.LAYOUT, // folder type - AndroidTargetData.DESCRIPTOR_LAYOUT, // root seed - "LinearLayout", // default root - SdkConstants.NS_RESOURCES, // xmlns - "android:layout_width=\"wrap_content\"\n" + // default attributes - "android:layout_height=\"wrap_content\"" - ), - new TypeInfo("Values", // UI name - "An XML file with simple values: colors, strings, dimensions, etc.", // tooltip - ResourceFolderType.VALUES, // folder type - ResourcesDescriptors.ROOT_ELEMENT, // root seed - null, // default root - null, // xmlns - null // default attributes - ), - new TypeInfo("Menu", // UI name - "An XML file that describes an menu.", // tooltip - ResourceFolderType.MENU, // folder type - MenuDescriptors.MENU_ROOT_ELEMENT, // root seed - null, // default root - SdkConstants.NS_RESOURCES, // xmlns - null // default attributes - ), - new TypeInfo("Preference", // UI name - "An XML file that describes preferences.", // tooltip - ResourceFolderType.XML, // folder type - AndroidTargetData.DESCRIPTOR_PREFERENCES, // root seed - AndroidConstants.CLASS_PREFERENCE_SCREEN, // default root - SdkConstants.NS_RESOURCES, // xmlns - null // default attributes - ), - new TypeInfo("Searchable", // UI name - "An XML file that describes a searchable [TODO].", // tooltip - ResourceFolderType.XML, // folder type - AndroidTargetData.DESCRIPTOR_SEARCHABLE, // root seed - null, // default root - SdkConstants.NS_RESOURCES, // xmlns - null // default attributes - ), - new TypeInfo("Animation", // UI name - "An XML file that describes an animation.", // tooltip - ResourceFolderType.ANIM, // folder type - // TODO reuse constants if we ever make an editor with descriptors for animations - new String[] { // root seed - "set", //$NON-NLS-1$ - "alpha", //$NON-NLS-1$ - "scale", //$NON-NLS-1$ - "translate", //$NON-NLS-1$ - "rotate" //$NON-NLS-1$ - }, - "set", //$NON-NLS-1$ // default root - null, // xmlns - null // default attributes - ), - }; - - /** Absolute destination folder root, e.g. "/res/" */ - private static String sResFolderAbs = AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP; - /** Relative destination folder root, e.g. "res/" */ - private static String sResFolderRel = SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP; - - private IProject mProject; - private Text mProjectTextField; - private Button mProjectBrowseButton; - private Text mFileNameTextField; - private Text mWsFolderPathTextField; - private Combo mRootElementCombo; - private IStructuredSelection mInitialSelection; - private ConfigurationSelector mConfigSelector; - private FolderConfiguration mTempConfig = new FolderConfiguration(); - private boolean mInternalWsFolderPathUpdate; - private boolean mInternalTypeUpdate; - private boolean mInternalConfigSelectorUpdate; - private ProjectChooserHelper mProjectChooserHelper; - - - // --- UI creation --- - - /** - * Constructs a new {@link NewXmlFileCreationPage}. - * <p/> - * Called by {@link NewXmlFileWizard#createMainPage()}. - */ - protected NewXmlFileCreationPage(String pageName) { - super(pageName); - setPageComplete(false); - } - - public void setInitialSelection(IStructuredSelection initialSelection) { - mInitialSelection = initialSelection; - } - - /** - * Called by the parent Wizard to create the UI for this Wizard Page. - * - * {@inheritDoc} - * - * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) - */ - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - composite.setFont(parent.getFont()); - - initializeDialogUnits(parent); - - composite.setLayout(new GridLayout(3, false /*makeColumnsEqualWidth*/)); - composite.setLayoutData(new GridData(GridData.FILL_BOTH)); - - createProjectGroup(composite); - createTypeGroup(composite); - createRootGroup(composite); - - // Show description the first time - setErrorMessage(null); - setMessage(null); - setControl(composite); - - // Update state the first time - initializeRootValues(); - initializeFromSelection(mInitialSelection); - validatePage(); - } - - /** - * Returns the target project or null. - */ - public IProject getProject() { - return mProject; - } - - /** - * Returns the destination filename or an empty string. - */ - public String getFileName() { - return mFileNameTextField == null ? "" : mFileNameTextField.getText(); //$NON-NLS-1$ - } - - /** - * Returns the destination folder path relative to the project or an empty string. - */ - public String getWsFolderPath() { - return mWsFolderPathTextField == null ? "" : mWsFolderPathTextField.getText(); //$NON-NLS-1$ - } - - - /** - * Returns an {@link IFile} on the destination file. - * <p/> - * Uses {@link #getProject()}, {@link #getWsFolderPath()} and {@link #getFileName()}. - * <p/> - * Returns null if the project, filename or folder are invalid and the destination file - * cannot be determined. - * <p/> - * The {@link IFile} is a resource. There might or might not be an actual real file. - */ - public IFile getDestinationFile() { - IProject project = getProject(); - String wsFolderPath = getWsFolderPath(); - String fileName = getFileName(); - if (project != null && wsFolderPath.length() > 0 && fileName.length() > 0) { - IPath dest = new Path(wsFolderPath).append(fileName); - IFile file = project.getFile(dest); - return file; - } - return null; - } - - /** - * Returns the {@link TypeInfo} for the currently selected type radio button. - * Returns null if no radio button is selected. - * - * @return A {@link TypeInfo} or null. - */ - public TypeInfo getSelectedType() { - TypeInfo type = null; - for (TypeInfo ti : sTypes) { - if (ti.getWidget().getSelection()) { - type = ti; - break; - } - } - return type; - } - - /** - * Returns the selected root element string, if any. - * - * @return The selected root element string or null. - */ - public String getRootElement() { - int index = mRootElementCombo.getSelectionIndex(); - if (index >= 0) { - return mRootElementCombo.getItem(index); - } - return null; - } - - // --- UI creation --- - - /** - * Helper method to create a new GridData with an horizontal span. - * - * @param horizSpan The number of cells for the horizontal span. - * @return A new GridData with the horizontal span. - */ - private GridData newGridData(int horizSpan) { - GridData gd = new GridData(); - gd.horizontalSpan = horizSpan; - return gd; - } - - /** - * Helper method to create a new GridData with an horizontal span and a style. - * - * @param horizSpan The number of cells for the horizontal span. - * @param style The style, e.g. {@link GridData#FILL_HORIZONTAL} - * @return A new GridData with the horizontal span and the style. - */ - private GridData newGridData(int horizSpan, int style) { - GridData gd = new GridData(style); - gd.horizontalSpan = horizSpan; - return gd; - } - - /** - * Helper method that creates an empty cell in the parent composite. - * - * @param parent The parent composite. - */ - private void emptyCell(Composite parent) { - new Label(parent, SWT.NONE); - } - - /** - * Creates the project & filename fields. - * <p/> - * The parent must be a GridLayout with 3 colums. - */ - private void createProjectGroup(Composite parent) { - // project name - String tooltip = "The Android Project where the new resource file will be created."; - Label label = new Label(parent, SWT.NONE); - label.setText("Project"); - label.setToolTipText(tooltip); - - mProjectTextField = new Text(parent, SWT.BORDER); - mProjectTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mProjectTextField.setToolTipText(tooltip); - mProjectTextField.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onProjectFieldUpdated(); - } - }); - - mProjectBrowseButton = new Button(parent, SWT.NONE); - mProjectBrowseButton.setText("Browse..."); - mProjectBrowseButton.setToolTipText("Allows you to select the Android project to modify."); - mProjectBrowseButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onProjectBrowse(); - } - }); - mProjectChooserHelper = new ProjectChooserHelper(parent.getShell()); - - // file name - tooltip = "The name of the resource file to create."; - label = new Label(parent, SWT.NONE); - label.setText("File"); - label.setToolTipText(tooltip); - - mFileNameTextField = new Text(parent, SWT.BORDER); - mFileNameTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mFileNameTextField.setToolTipText(tooltip); - mFileNameTextField.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - validatePage(); - } - }); - - emptyCell(parent); - } - - /** - * Creates the type field, {@link ConfigurationSelector} and the folder field. - * <p/> - * The parent must be a GridLayout with 3 colums. - */ - private void createTypeGroup(Composite parent) { - // separator - Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); - label.setLayoutData(newGridData(3, GridData.GRAB_HORIZONTAL)); - - // label before type radios - label = new Label(parent, SWT.NONE); - label.setText("What type of resource would you like to create?"); - label.setLayoutData(newGridData(3)); - - // display the types on three columns of radio buttons. - emptyCell(parent); - Composite grid = new Composite(parent, SWT.NONE); - emptyCell(parent); - - grid.setLayout(new GridLayout(3, true /*makeColumnsEqualWidth*/)); - - SelectionListener radioListener = new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - // single-click. Only do something if activated. - if (e.getSource() instanceof Button) { - onRadioTypeUpdated((Button) e.getSource()); - } - } - }; - - int n = sTypes.length; - int num_lines = n/3; - for (int line = 0; line < num_lines; line++) { - for (int i = 0; i < 3; i++) { - TypeInfo type = sTypes[line * 3 + i]; - Button radio = new Button(grid, SWT.RADIO); - type.setWidget(radio); - radio.setSelection(false); - radio.setText(type.getUiName()); - radio.setToolTipText(type.getTooltip()); - radio.addSelectionListener(radioListener); - } - } - - // label before configuration selector - label = new Label(parent, SWT.NONE); - label.setText("What type of resource configuration would you like?"); - label.setLayoutData(newGridData(3)); - - // configuration selector - emptyCell(parent); - mConfigSelector = new ConfigurationSelector(parent); - GridData gd = newGridData(2, GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); - gd.widthHint = ConfigurationSelector.WIDTH_HINT; - gd.heightHint = ConfigurationSelector.HEIGHT_HINT; - mConfigSelector.setLayoutData(gd); - mConfigSelector.setOnChangeListener(new onConfigSelectorUpdated()); - - // folder name - String tooltip = "The folder where the file will be generated, relative to the project."; - label = new Label(parent, SWT.NONE); - label.setText("Folder"); - label.setToolTipText(tooltip); - - mWsFolderPathTextField = new Text(parent, SWT.BORDER); - mWsFolderPathTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mWsFolderPathTextField.setToolTipText(tooltip); - mWsFolderPathTextField.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - onWsFolderPathUpdated(); - } - }); - - emptyCell(parent); - } - - /** - * Creates the root element combo. - * <p/> - * The parent must be a GridLayout with 3 colums. - */ - private void createRootGroup(Composite parent) { - // separator - Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); - label.setLayoutData(newGridData(3, GridData.GRAB_HORIZONTAL)); - - // label before the root combo - String tooltip = "The root element to create in the XML file."; - label = new Label(parent, SWT.NONE); - label.setText("Select the root element for the XML file:"); - label.setLayoutData(newGridData(3)); - label.setToolTipText(tooltip); - - // root combo - emptyCell(parent); - - mRootElementCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY); - mRootElementCombo.setEnabled(false); - mRootElementCombo.select(0); - mRootElementCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mRootElementCombo.setToolTipText(tooltip); - - emptyCell(parent); - } - - /** - * Called by {@link NewXmlFileWizard} to initialize the page with the selection - * received by the wizard -- typically the current user workbench selection. - * <p/> - * Things we expect to find out from the selection: - * <ul> - * <li>The project name, valid if it's an android nature.</li> - * <li>The current folder, valid if it's a folder under /res</li> - * <li>An existing filename, in which case the user will be asked whether to override it.</li> - * <ul> - * - * @param selection The selection when the wizard was initiated. - */ - private void initializeFromSelection(IStructuredSelection selection) { - if (selection == null) { - return; - } - - - // Find the best match in the element list. In case there are multiple selected elements - // select the one that provides the most information and assign them a score, - // e.g. project=1 + folder=2 + file=4. - IProject targetProject = null; - String targetWsFolderPath = null; - String targetFileName = null; - int targetScore = 0; - for (Object element : selection.toList()) { - if (element instanceof IAdaptable) { - IResource res = (IResource) ((IAdaptable) element).getAdapter(IResource.class); - IProject project = res != null ? res.getProject() : null; - - // Is this an Android project? - try { - if (project == null || !project.hasNature(AndroidConstants.NATURE)) { - continue; - } - } catch (CoreException e) { - // checking the nature failed, ignore this resource - continue; - } - - int score = 1; // we have a valid project at least - - IPath wsFolderPath = null; - String fileName = null; - if (res.getType() == IResource.FOLDER) { - wsFolderPath = res.getProjectRelativePath(); - } else if (res.getType() == IResource.FILE) { - fileName = res.getName(); - wsFolderPath = res.getParent().getProjectRelativePath(); - } - - // Disregard this folder selection if it doesn't point to /res/something - if (wsFolderPath != null && - wsFolderPath.segmentCount() > 1 && - SdkConstants.FD_RESOURCES.equals(wsFolderPath.segment(0))) { - score += 2; - } else { - wsFolderPath = null; - fileName = null; - } - - score += fileName != null ? 4 : 0; - - if (score > targetScore) { - targetScore = score; - targetProject = project; - targetWsFolderPath = wsFolderPath != null ? wsFolderPath.toString() : null; - targetFileName = fileName; - } - } - } - - // Now set the UI accordingly - if (targetScore > 0) { - mProject = targetProject; - mProjectTextField.setText(targetProject != null ? targetProject.getName() : ""); //$NON-NLS-1$ - mFileNameTextField.setText(targetFileName != null ? targetFileName : ""); //$NON-NLS-1$ - mWsFolderPathTextField.setText(targetWsFolderPath != null ? targetWsFolderPath : ""); //$NON-NLS-1$ - } - } - - /** - * Initialize the root values of the type infos based on the current framework values. - */ - private void initializeRootValues() { - for (TypeInfo type : sTypes) { - // Clear all the roots for this type - ArrayList<String> roots = type.getRoots(); - if (roots.size() > 0) { - roots.clear(); - } - - // depending of the type of the seed, initialize the root in different ways - Object rootSeed = type.getRootSeed(); - - if (rootSeed instanceof String) { - // The seed is a single string, Add it as-is. - roots.add((String) rootSeed); - } else if (rootSeed instanceof String[]) { - // The seed is an array of strings. Add them as-is. - for (String value : (String[]) rootSeed) { - roots.add(value); - } - } else if (rootSeed instanceof Integer && mProject != null) { - // The seed is a descriptor reference defined in AndroidTargetData.DESCRIPTOR_* - // In this case add all the children element descriptors defined, recursively, - // and avoid infinite recursion by keeping track of what has already been added. - - // Note: if project is null, the root list will be empty since it has been - // cleared above. - - // get the AndroidTargetData from the project - IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); - AndroidTargetData data = Sdk.getCurrent().getTargetData(target); - ElementDescriptor descriptor = data.getDescriptorProvider( - (Integer)rootSeed).getDescriptor(); - - HashSet<ElementDescriptor> visited = new HashSet<ElementDescriptor>(); - initRootElementDescriptor(roots, descriptor, visited); - - // Sort alphabetically. - Collections.sort(roots); - } - } - } - - /** - * Helper method to recursively insert all XML names for the given {@link ElementDescriptor} - * into the roots array list. Keeps track of visited nodes to avoid infinite recursion. - * Also avoids inserting the top {@link DocumentDescriptor} which is generally synthetic - * and not a valid root element. - */ - private void initRootElementDescriptor(ArrayList<String> roots, - ElementDescriptor desc, HashSet<ElementDescriptor> visited) { - if (!(desc instanceof DocumentDescriptor)) { - String xmlName = desc.getXmlName(); - if (xmlName != null && xmlName.length() > 0) { - roots.add(xmlName); - } - } - - visited.add(desc); - - for (ElementDescriptor child : desc.getChildren()) { - if (!visited.contains(child)) { - initRootElementDescriptor(roots, child, visited); - } - } - } - - /** - * Callback called when the user edits the project text field. - */ - private void onProjectFieldUpdated() { - String project = mProjectTextField.getText(); - - // Is this a valid project? - IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null /*javaModel*/); - IProject found = null; - for (IJavaProject p : projects) { - if (p.getProject().getName().equals(project)) { - found = p.getProject(); - break; - } - } - - if (found != mProject) { - mProject = found; - - // update the Type with the new descriptors. - initializeRootValues(); - - // update the combo - updateRootCombo(getSelectedType()); - - validatePage(); - } - } - - /** - * Callback called when the user uses the "Browse Projects" button. - */ - private void onProjectBrowse() { - IJavaProject p = mProjectChooserHelper.chooseJavaProject(mProjectTextField.getText()); - if (p != null) { - mProject = p.getProject(); - mProjectTextField.setText(mProject.getName()); - - // update the Type with the new descriptors. - initializeRootValues(); - - // update the combo - updateRootCombo(getSelectedType()); - - validatePage(); - } - } - - /** - * Callback called when the Folder text field is changed, either programmatically - * or by the user. - */ - private void onWsFolderPathUpdated() { - if (mInternalWsFolderPathUpdate) { - return; - } - - String wsFolderPath = mWsFolderPathTextField.getText(); - - // This is a custom path, we need to sanitize it. - // First it should start with "/res/". Then we need to make sure there are no - // relative paths, things like "../" or "./" or even "//". - wsFolderPath = wsFolderPath.replaceAll("/+\\.\\./+|/+\\./+|//+|\\\\+|^/+", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - wsFolderPath = wsFolderPath.replaceAll("^\\.\\./+|^\\./+", ""); //$NON-NLS-1$ //$NON-NLS-2$ - wsFolderPath = wsFolderPath.replaceAll("/+\\.\\.$|/+\\.$|/+$", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - ArrayList<TypeInfo> matches = new ArrayList<TypeInfo>(); - - // We get "res/foo" from selections relative to the project when we want a "/res/foo" path. - if (wsFolderPath.startsWith(sResFolderRel)) { - wsFolderPath = sResFolderAbs + wsFolderPath.substring(sResFolderRel.length()); - - mInternalWsFolderPathUpdate = true; - mWsFolderPathTextField.setText(wsFolderPath); - mInternalWsFolderPathUpdate = false; - } - - if (wsFolderPath.startsWith(sResFolderAbs)) { - wsFolderPath = wsFolderPath.substring(sResFolderAbs.length()); - - int pos = wsFolderPath.indexOf(AndroidConstants.WS_SEP_CHAR); - if (pos >= 0) { - wsFolderPath = wsFolderPath.substring(0, pos); - } - - String[] folderSegments = wsFolderPath.split(FolderConfiguration.QUALIFIER_SEP); - - if (folderSegments.length > 0) { - String folderName = folderSegments[0]; - - // update config selector - mInternalConfigSelectorUpdate = true; - mConfigSelector.setConfiguration(folderSegments); - mInternalConfigSelectorUpdate = false; - - boolean selected = false; - for (TypeInfo type : sTypes) { - if (type.getResFolderName().equals(folderName)) { - matches.add(type); - selected |= type.getWidget().getSelection(); - } - } - - if (matches.size() == 1) { - // If there's only one match, select it if it's not already selected - if (!selected) { - selectType(matches.get(0)); - } - } else if (matches.size() > 1) { - // There are multiple type candidates for this folder. This can happen - // for /res/xml for example. Check to see if one of them is currently - // selected. If yes, leave the selection unchanged. If not, deselect all type. - if (!selected) { - selectType(null); - } - } else { - // Nothing valid was selected. - selectType(null); - } - } - } - - validatePage(); - } - - /** - * Callback called when one of the type radio button is changed. - * - * @param typeWidget The type radio button that changed. - */ - private void onRadioTypeUpdated(Button typeWidget) { - // Do nothing if this is an internal modification or if the widget has been - // de-selected. - if (mInternalTypeUpdate || !typeWidget.getSelection()) { - return; - } - - // Find type info that has just been enabled. - TypeInfo type = null; - for (TypeInfo ti : sTypes) { - if (ti.getWidget() == typeWidget) { - type = ti; - break; - } - } - - if (type == null) { - return; - } - - // update the combo - - updateRootCombo(type); - - // update the folder path - - String wsFolderPath = mWsFolderPathTextField.getText(); - String newPath = null; - - mConfigSelector.getConfiguration(mTempConfig); - ResourceQualifier qual = mTempConfig.getInvalidQualifier(); - if (qual == null) { - // The configuration is valid. Reformat the folder path using the canonical - // value from the configuration. - - newPath = sResFolderAbs + mTempConfig.getFolderName(type.getResFolderType()); - } else { - // The configuration is invalid. We still update the path but this time - // do it manually on the string. - if (wsFolderPath.startsWith(sResFolderAbs)) { - wsFolderPath.replaceFirst( - "^(" + sResFolderAbs +")[^-]*(.*)", //$NON-NLS-1$ //$NON-NLS-2$ - "\\1" + type.getResFolderName() + "\\2"); //$NON-NLS-1$ //$NON-NLS-2$ - } else { - newPath = sResFolderAbs + mTempConfig.getFolderName(type.getResFolderType()); - } - } - - if (newPath != null && !newPath.equals(wsFolderPath)) { - mInternalWsFolderPathUpdate = true; - mWsFolderPathTextField.setText(newPath); - mInternalWsFolderPathUpdate = false; - } - - validatePage(); - } - - /** - * Helper method that fills the values of the "root element" combo box based - * on the currently selected type radio button. Also disables the combo is there's - * only one choice. Always select the first root element for the given type. - * - * @param type The currently selected {@link TypeInfo}. Cannot be null. - */ - private void updateRootCombo(TypeInfo type) { - // reset all the values in the combo - mRootElementCombo.removeAll(); - - if (type != null) { - // get the list of roots. The list can be empty but not null. - ArrayList<String> roots = type.getRoots(); - - // enable the combo if there's more than one choice - mRootElementCombo.setEnabled(roots != null && roots.size() > 1); - - for (String root : roots) { - mRootElementCombo.add(root); - } - - int index = 0; // default is to select the first one - String defaultRoot = type.getDefaultRoot(); - if (defaultRoot != null) { - index = roots.indexOf(defaultRoot); - } - mRootElementCombo.select(index < 0 ? 0 : index); - } - } - - /** - * Callback called when the configuration has changed in the {@link ConfigurationSelector}. - */ - private class onConfigSelectorUpdated implements Runnable { - public void run() { - if (mInternalConfigSelectorUpdate) { - return; - } - - TypeInfo type = getSelectedType(); - - if (type != null) { - mConfigSelector.getConfiguration(mTempConfig); - StringBuffer sb = new StringBuffer(sResFolderAbs); - sb.append(mTempConfig.getFolderName(type.getResFolderType())); - - mInternalWsFolderPathUpdate = true; - mWsFolderPathTextField.setText(sb.toString()); - mInternalWsFolderPathUpdate = false; - - validatePage(); - } - } - } - - /** - * Helper method to select on of the type radio buttons. - * - * @param type The TypeInfo matching the radio button to selected or null to deselect them all. - */ - private void selectType(TypeInfo type) { - if (type == null || !type.getWidget().getSelection()) { - mInternalTypeUpdate = true; - for (TypeInfo type2 : sTypes) { - type2.getWidget().setSelection(type2 == type); - } - updateRootCombo(type); - mInternalTypeUpdate = false; - } - } - - /** - * Validates the fields, displays errors and warnings. - * Enables the finish button if there are no errors. - */ - private void validatePage() { - String error = null; - String warning = null; - - // -- validate project - if (getProject() == null) { - error = "Please select an Android project."; - } - - // -- validate filename - if (error == null) { - String fileName = getFileName(); - if (fileName == null || fileName.length() == 0) { - error = "A destination file name is required."; - } else if (!fileName.endsWith(AndroidConstants.DOT_XML)) { - error = String.format("The filename must end with %1$s.", AndroidConstants.DOT_XML); - } - } - - // -- validate type - if (error == null) { - TypeInfo type = getSelectedType(); - - if (type == null) { - error = "One of the types must be selected (e.g. layout, values, etc.)"; - } - } - - // -- validate folder configuration - if (error == null) { - ConfigurationState state = mConfigSelector.getState(); - if (state == ConfigurationState.INVALID_CONFIG) { - ResourceQualifier qual = mConfigSelector.getInvalidQualifier(); - if (qual != null) { - error = String.format("The qualifier '%1$s' is invalid in the folder configuration.", - qual.getName()); - } - } else if (state == ConfigurationState.REGION_WITHOUT_LANGUAGE) { - error = "The Region qualifier requires the Language qualifier."; - } - } - - // -- validate generated path - if (error == null) { - String wsFolderPath = getWsFolderPath(); - if (!wsFolderPath.startsWith(sResFolderAbs)) { - error = String.format("Target folder must start with %1$s.", sResFolderAbs); - } - } - - // -- validate destination file doesn't exist - if (error == null) { - IFile file = getDestinationFile(); - if (file != null && file.exists()) { - warning = "The destination file already exists"; - } - } - - // -- update UI & enable finish if there's no error - setPageComplete(error == null); - if (error != null) { - setMessage(error, WizardPage.ERROR); - } else if (warning != null) { - setMessage(warning, WizardPage.WARNING); - } else { - setErrorMessage(null); - setMessage(null); - } - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileWizard.java deleted file mode 100644 index 125102b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileWizard.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.wizards; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.wizards.NewXmlFileCreationPage.TypeInfo; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.ui.INewWizard; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.ide.IDE; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; - -/** - * The "New Android XML File Wizard" provides the ability to create skeleton XML - * resources files for Android projects. - * <p/> - * The wizard has one page, {@link NewXmlFileCreationPage}, used to select the project, - * the resource folder, resource type and file name. It then creates the XML file. - */ -public class NewXmlFileWizard extends Wizard implements INewWizard { - - private static final String PROJECT_LOGO_LARGE = "android_large"; //$NON-NLS-1$ - - protected static final String MAIN_PAGE_NAME = "newAndroidXmlFilePage"; //$NON-NLS-1$ - - private NewXmlFileCreationPage mMainPage; - - public void init(IWorkbench workbench, IStructuredSelection selection) { - setHelpAvailable(false); // TODO have help - setWindowTitle("New Android XML File"); - setImageDescriptor(); - - mMainPage = createMainPage(); - mMainPage.setTitle("New Android XML File"); - mMainPage.setDescription("Creates a new Android XML file."); - mMainPage.setInitialSelection(selection); - } - - /** - * Creates the wizard page. - * <p/> - * Please do NOT override this method. - * <p/> - * This is protected so that it can be overridden by unit tests. - * However the contract of this class is private and NO ATTEMPT will be made - * to maintain compatibility between different versions of the plugin. - */ - protected NewXmlFileCreationPage createMainPage() { - return new NewXmlFileCreationPage(MAIN_PAGE_NAME); - } - - // -- Methods inherited from org.eclipse.jface.wizard.Wizard -- - // - // The Wizard class implements most defaults and boilerplate code needed by - // IWizard - - /** - * Adds pages to this wizard. - */ - @Override - public void addPages() { - addPage(mMainPage); - } - - /** - * Performs any actions appropriate in response to the user having pressed - * the Finish button, or refuse if finishing now is not permitted: here, it - * actually creates the workspace project and then switch to the Java - * perspective. - * - * @return True - */ - @Override - public boolean performFinish() { - IFile file = createXmlFile(); - if (file == null) { - return false; - } else { - // Open the file in an editor - IWorkbenchWindow win = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (win != null) { - IWorkbenchPage page = win.getActivePage(); - if (page != null) { - try { - IDE.openEditor(page, file); - } catch (PartInitException e) { - AdtPlugin.log(e, "Failed to create %1$s: missing type", //$NON-NLS-1$ - file.getFullPath().toString()); - } - } - } - return true; - } - } - - // -- Custom Methods -- - - private IFile createXmlFile() { - IFile file = mMainPage.getDestinationFile(); - String name = file.getFullPath().toString(); - boolean need_delete = false; - - if (file.exists()) { - if (!AdtPlugin.displayPrompt("New Android XML File", - String.format("Do you want to overwrite the file %1$s ?", name))) { - // abort if user selects cancel. - return null; - } - need_delete = true; - } else { - createWsParentDirectory(file.getParent()); - } - - TypeInfo type = mMainPage.getSelectedType(); - if (type == null) { - // this is not expected to happen - AdtPlugin.log(IStatus.ERROR, "Failed to create %1$s: missing type", name); //$NON-NLS-1$ - return null; - } - String xmlns = type.getXmlns(); - String root = mMainPage.getRootElement(); - if (root == null) { - // this is not expected to happen - AdtPlugin.log(IStatus.ERROR, "Failed to create %1$s: missing root element", //$NON-NLS-1$ - file.toString()); - return null; - } - - StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$ - - sb.append('<').append(root); - if (xmlns != null) { - sb.append('\n').append(" xmlns:android=\"").append(xmlns).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ - } - - String attrs = type.getDefaultAttrs(); - if (attrs != null) { - sb.append("\n "); //$NON-NLS-1$ - sb.append(attrs.replace("\n", "\n ")); //$NON-NLS-1$ //$NON-NLS-2$ - } - - sb.append(">\n"); //$NON-NLS-1$ - sb.append("</").append(root).append(">\n"); //$NON-NLS-1$ //$NON-NLS-2$ - - String result = sb.toString(); - String error = null; - try { - byte[] buf = result.getBytes("UTF8"); - InputStream stream = new ByteArrayInputStream(buf); - if (need_delete) { - file.delete(IFile.KEEP_HISTORY | IFile.FORCE, null /*monitor*/); - } - file.create(stream, true /*force*/, null /*progres*/); - return file; - } catch (UnsupportedEncodingException e) { - error = e.getMessage(); - } catch (CoreException e) { - error = e.getMessage(); - } - - error = String.format("Failed to generate %1$s: %2$s", name, error); - AdtPlugin.displayError("New Android XML File", error); - return null; - } - - private boolean createWsParentDirectory(IContainer wsPath) { - if (wsPath.getType() == IContainer.FOLDER) { - if (wsPath == null || 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; - } - - /** - * Returns an image descriptor for the wizard logo. - */ - private void setImageDescriptor() { - ImageDescriptor desc = IconFactory.getInstance().getImageDescriptor(PROJECT_LOGO_LARGE); - setDefaultPageImageDescriptor(desc); - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java deleted file mode 100644 index 6913ce0..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.wizards; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.DialogSettings; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.IDialogSettings; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.ui.dialogs.FilteredTree; -import org.eclipse.ui.dialogs.PatternFilter; -import org.eclipse.ui.dialogs.SelectionStatusDialog; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A dialog to let the user choose a reference to a resource. - * - */ -public class ReferenceChooserDialog extends SelectionStatusDialog { - - private static Pattern sResourcePattern = Pattern.compile("@(.*)/(.+)"); //$NON-NLS-1$ - private static Pattern sInlineIdResourcePattern = Pattern.compile("@\\+id/(.+)"); //$NON-NLS-1$ - - private static IDialogSettings sDialogSettings = new DialogSettings(""); - - private IResourceRepository mResources; - private String mCurrentResource; - - private FilteredTree mFilteredTree; - - /** - * @param parent - */ - public ReferenceChooserDialog(IResourceRepository resources, Shell parent) { - super(parent); - - int shellStyle = getShellStyle(); - setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); - - setTitle("Reference Dialog"); - setMessage(String.format("Choose a resource")); - mResources = resources; - - setDialogBoundsSettings(sDialogSettings, getDialogBoundsStrategy()); - } - - public void setCurrentResource(String resource) { - mCurrentResource = resource; - } - - public String getCurrentResource() { - return mCurrentResource; - } - - - /* (non-Javadoc) - * @see org.eclipse.ui.dialogs.SelectionStatusDialog#computeResult() - */ - @Override - protected void computeResult() { - // get the selection - TreePath treeSelection = getSelection(); - if (treeSelection != null) { - if (treeSelection.getSegmentCount() == 2) { - // get the resource type and the resource item - ResourceType resourceType = (ResourceType)treeSelection.getFirstSegment(); - ResourceItem resourceItem = (ResourceItem)treeSelection.getLastSegment(); - - mCurrentResource = resourceType.getXmlString(resourceItem, false /* system */); - } - } - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite top = (Composite)super.createDialogArea(parent); - - // create the standard message area - createMessageArea(top); - - // create the filtered tree - createFilteredTree(top); - - // setup the initial selection - setupInitialSelection(); - - return top; - } - - private void createFilteredTree(Composite parent) { - mFilteredTree = new FilteredTree(parent, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION, - new PatternFilter()); - - GridData data = new GridData(); - data.widthHint = convertWidthInCharsToPixels(60); - data.heightHint = convertHeightInCharsToPixels(18); - data.grabExcessVerticalSpace = true; - data.grabExcessHorizontalSpace = true; - data.horizontalAlignment = GridData.FILL; - data.verticalAlignment = GridData.FILL; - mFilteredTree.setLayoutData(data); - mFilteredTree.setFont(parent.getFont()); - - TreeViewer treeViewer = mFilteredTree.getViewer(); - Tree tree = treeViewer.getTree(); - - tree.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - handleDoubleClick(); - } - - public void widgetSelected(SelectionEvent e) { - handleSelection(); - } - }); - - treeViewer.setLabelProvider(new ResourceLabelProvider()); - treeViewer.setContentProvider(new ResourceContentProvider(false /* fullLevels */)); - treeViewer.setInput(mResources); - } - - protected void handleSelection() { - validateCurrentSelection(); - } - - protected void handleDoubleClick() { - if (validateCurrentSelection()) { - buttonPressed(IDialogConstants.OK_ID); - } - } - - /** - * Returns the selected item in the tree as a {@link TreePath} object. - * @return the <code>TreePath</code> object or <code>null</code> if there was no selection. - */ - private TreePath getSelection() { - ISelection selection = mFilteredTree.getViewer().getSelection(); - if (selection instanceof TreeSelection) { - TreeSelection treeSelection = (TreeSelection)selection; - TreePath[] treePaths = treeSelection.getPaths(); - - // the selection mode is SWT.SINGLE, so we just get the first one. - if (treePaths.length > 0) { - return treePaths[0]; - } - } - - return null; - } - - private boolean validateCurrentSelection() { - TreePath treeSelection = getSelection(); - - IStatus status; - if (treeSelection != null) { - if (treeSelection.getSegmentCount() == 2) { - status = new Status(IStatus.OK, AdtPlugin.PLUGIN_ID, - IStatus.OK, "", //$NON-NLS-1$ - null); - } else { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - IStatus.ERROR, "You must select a Resource Item", - null); - } - } else { - status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, - IStatus.ERROR, "", //$NON-NLS-1$ - null); - } - - updateStatus(status); - - return status.isOK(); - } - - /** - * Sets up the initial selection. - * <p/> - * This parses {@link #mCurrentResource} to find out the resource type and the resource name. - */ - private void setupInitialSelection() { - // checks the inline id pattern first as it's more restrictive than the other one. - Matcher m = sInlineIdResourcePattern.matcher(mCurrentResource); - if (m.matches()) { - // get the matching name - String resourceName = m.group(1); - - // setup initial selection - setupInitialSelection(ResourceType.ID, resourceName); - } else { - // attempts the inline id pattern - m = sResourcePattern.matcher(mCurrentResource); - if (m.matches()) { - // get the resource type. - ResourceType resourceType = ResourceType.getEnum(m.group(1)); - if (resourceType != null) { - // get the matching name - String resourceName = m.group(2); - - // setup initial selection - setupInitialSelection(resourceType, resourceName); - } - } - } - } - - /** - * Sets up the initial selection based on a {@link ResourceType} and a resource name. - * @param resourceType the resource type. - * @param resourceName the resource name. - */ - private void setupInitialSelection(ResourceType resourceType, String resourceName) { - // get all the resources of this type - ResourceItem[] resourceItems = mResources.getResources(resourceType); - - for (ResourceItem resourceItem : resourceItems) { - if (resourceName.equals(resourceItem.getName())) { - // name of the resource match, we select it, - TreePath treePath = new TreePath(new Object[] { resourceType, resourceItem }); - mFilteredTree.getViewer().setSelection(new TreeSelection(treePath)); - - // and we're done. - return; - } - } - - // if we get here, the resource type is valid, but the resource is missing. - // we select and expand the resource type element. - TreePath treePath = new TreePath(new Object[] { resourceType }); - mFilteredTree.getViewer().setSelection(new TreeSelection(treePath)); - mFilteredTree.getViewer().setExpandedState(resourceType, true /* expanded */); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceChooser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceChooser.java deleted file mode 100644 index 60a627b..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceChooser.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.wizards; - -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.dialogs.AbstractElementListSelectionDialog; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A dialog to let the user select a resource based on a resource type. - */ -public class ResourceChooser extends AbstractElementListSelectionDialog { - - private Pattern mProjectResourcePattern; - - private ResourceType mResourceType; - - private IResourceRepository mProjectResources; - - // TODO: enable when we can display the system resources. - // private Pattern mSystemResourcePattern; - // private IResourceRepository mSystemResources; - // private Button mProjectButton; - // private Button mSystemButton; - - private String mCurrentResource; - - /** - * Creates a Resource Chooser dialog. - * @param type The type of the resource to choose - * @param project The repository for the project - * @param system The System resource repository - * @param parent the parent shell - */ - public ResourceChooser(ResourceType type, IResourceRepository project, - IResourceRepository system, Shell parent) { - super(parent, new ResourceLabelProvider()); - - mResourceType = type; - mProjectResources = project; - // TODO: enable when we can display the system resources. - // mSystemResources = system; - - mProjectResourcePattern = Pattern.compile( - "@" + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ //$NON-NLS-2$ - // TODO: enable when we can display the system resources. - // mSystemResourcePattern = Pattern.compile( - // "@android:" + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ //$NON-NLS-2$ - - setTitle("Resource Chooser"); - setMessage(String.format("Choose a %1$s resource", - mResourceType.getDisplayName().toLowerCase())); - } - - public void setCurrentResource(String resource) { - mCurrentResource = resource; - } - - public String getCurrentResource() { - return mCurrentResource; - } - - @Override - protected void computeResult() { - Object[] elements = getSelectedElements(); - if (elements.length == 1 && elements[0] instanceof ResourceItem) { - ResourceItem item = (ResourceItem)elements[0]; - - mCurrentResource = mResourceType.getXmlString(item, - // TODO: enable when we can display the system resources. - false /*mSystemButton.getSelection()*/); - } - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite top = (Composite)super.createDialogArea(parent); - - createMessageArea(top); - - // TODO: enable when we can display the system resources. - // createButtons(top); - - createFilterText(top); - createFilteredList(top); - - setupResourceListAndCurrent(); - - return top; - } - - /** - * Creates the radio button to switch between project and system resources. - * @param top the parent composite - */ - /* TODO: enable when we can display the system resources. - private void createButtons(Composite top) { - mProjectButton = new Button(top, SWT.RADIO); - mProjectButton.setText("Project Resources"); - mProjectButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - setListElements(mProjectResources.getResources(mResourceType)); - } - }); - mSystemButton = new Button(top, SWT.RADIO); - mSystemButton.setText("System Resources"); - mSystemButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - super.widgetSelected(e); - setListElements(mSystemResources.getResources(mResourceType)); - } - }); - } - */ - - /** - * Setups the current list based on the current resource. - */ - private void setupResourceListAndCurrent() { - if (setupInitialSelection(mProjectResourcePattern, mProjectResources) == false) { - // if we couldn't understand the current value, we default to the project resources - ResourceItem[] items = mProjectResources.getResources(mResourceType); - setListElements(items); - } - /* - * TODO: enable when we can display the system resources. - if (setupInitialSelection(mProjectResourcePattern, mProjectResources) == false) { - if (setupInitialSelection(mSystemResourcePattern, mSystemResources) == false) { - // if we couldn't understand the current value, we default to the project resources - IResourceItem[] items = mProjectResources.getResources(mResourceType); - setListElements(items); - mProjectButton.setSelection(true); - } else { - mSystemButton.setSelection(true); - } - } else { - mProjectButton.setSelection(true); - }*/ - } - - /** - * Attempts to setup the list of element from a repository if the current resource - * matches the provided pattern. - * @param pattern the pattern to test the current value - * @param repository the repository to use if the pattern matches. - * @return true if success. - */ - private boolean setupInitialSelection(Pattern pattern, IResourceRepository repository) { - Matcher m = pattern.matcher(mCurrentResource); - if (m.matches()) { - // we have a project resource, let's setup the list - ResourceItem[] items = repository.getResources(mResourceType); - setListElements(items); - - // and let's look for the item we found - String name = m.group(1); - - for (ResourceItem item : items) { - if (name.equals(item.getName())) { - setSelection(new Object[] { item }); - break; - } - } - return true; - } - return false; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceContentProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceContentProvider.java deleted file mode 100644 index 7c6a539..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceContentProvider.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.wizards; - -import com.android.ide.eclipse.common.resources.IResourceRepository; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.manager.ConfigurableResourceItem; -import com.android.ide.eclipse.editors.resources.manager.ResourceFile; - -import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.Viewer; - -/** - * Content provider for the Resource Explorer TreeView. - * Each level of the tree is represented by a different class. - * <ul> - * <li>{@link ResourceType}. This represents the list of existing Resource Type present - * in the resources. This can be matched to the subclasses inside the class <code>R</code> - * </li> - * <ul> - * <li>{@link ResourceItem}. This represents one resource (which can existing in various alternate - * versions). This is similar to the resource Ids defined as <code>R.sometype.id</code>. - * </li> - * <ul> - * <li>{@link ResourceFile}. (optional) This represents a particular version of the - * {@link ResourceItem}. It is displayed as a list of resource qualifier. - * </li> - * </ul> - * </ul> - * </ul> - * - * @see ResourceLabelProvider - */ -public class ResourceContentProvider implements ITreeContentProvider { - - /** - * The current ProjectResources being displayed. - */ - private IResourceRepository mResources; - - private boolean mFullLevels; - - /** - * Constructs a new content providers for resource display. - * @param fullLevels if <code>true</code> the content provider will suppport all 3 levels. If - * <code>false</code>, only two levels are provided. - */ - public ResourceContentProvider(boolean fullLevels) { - mFullLevels = fullLevels; - } - - public Object[] getChildren(Object parentElement) { - if (parentElement instanceof ResourceType) { - return mResources.getResources((ResourceType)parentElement); - } else if (mFullLevels && parentElement instanceof ConfigurableResourceItem) { - return ((ConfigurableResourceItem)parentElement).getSourceFileArray(); - } - return null; - } - - public Object getParent(Object element) { - // pass - return null; - } - - public boolean hasChildren(Object element) { - if (element instanceof ResourceType) { - return mResources.hasResources((ResourceType)element); - } else if (mFullLevels && element instanceof ConfigurableResourceItem) { - return ((ConfigurableResourceItem)element).hasAlternates(); - } - return false; - } - - public Object[] getElements(Object inputElement) { - if (inputElement instanceof IResourceRepository) { - if ((IResourceRepository)inputElement == mResources) { - // get the top level resources. - return mResources.getAvailableResourceTypes(); - } - } - - return new Object[0]; - } - - public void dispose() { - // pass - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - if (newInput instanceof IResourceRepository) { - mResources = (IResourceRepository)newInput; - } - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceLabelProvider.java deleted file mode 100644 index 024d084..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceLabelProvider.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2007 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.editors.wizards; - -import com.android.ide.eclipse.common.resources.IIdResourceItem; -import com.android.ide.eclipse.common.resources.ResourceItem; -import com.android.ide.eclipse.common.resources.ResourceType; -import com.android.ide.eclipse.editors.resources.manager.ConfigurableResourceItem; -import com.android.ide.eclipse.editors.resources.manager.IdResourceItem; -import com.android.ide.eclipse.editors.resources.manager.ResourceFile; - -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.swt.graphics.Image; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; - -/** - * Label provider for the Resource Explorer TreeView. - * Each level of the tree is represented by a different class. - * <ul> - * <li>{@link ResourceType}. This represents the list of existing Resource Type present - * in the resources. This can be matched to the subclasses inside the class <code>R</code> - * </li> - * <ul> - * <li>{@link ResourceItem}. This represents one resource. The actual type can be - * {@link ConfigurableResourceItem} (which can exist in various alternate versions), - * or {@link IdResourceItem}. - * This is similar to the resource Ids defined as <code>R.sometype.id</code>. - * </li> - * <ul> - * <li>{@link ResourceFile}. This represents a particular version of the {@link ResourceItem}. - * It is displayed as a list of resource qualifier. - * </li> - * </ul> - * </ul> - * </ul> - * - * @see ResourceContentProvider - */ -public class ResourceLabelProvider implements ILabelProvider, ITableLabelProvider { - private Image mWarningImage; - - public ResourceLabelProvider() { - mWarningImage = PlatformUI.getWorkbench().getSharedImages().getImageDescriptor( - ISharedImages.IMG_OBJS_WARN_TSK).createImage(); - } - - /** - * @see #getColumnImage(Object, int) - */ - public Image getImage(Object element) { - // pass - return null; - } - - /** - * @see #getColumnText(Object, int) - */ - public String getText(Object element) { - return getColumnText(element, 0); - } - - public void addListener(ILabelProviderListener listener) { - // pass - } - - public void dispose() { - mWarningImage.dispose(); - } - - public boolean isLabelProperty(Object element, String property) { - return false; - } - - public void removeListener(ILabelProviderListener listener) { - // pass - } - - public Image getColumnImage(Object element, int columnIndex) { - if (columnIndex == 1) { - if (element instanceof ConfigurableResourceItem) { - ConfigurableResourceItem item = (ConfigurableResourceItem)element; - if (item.hasDefault() == false) { - return mWarningImage; - } - } - } - return null; - } - - public String getColumnText(Object element, int columnIndex) { - switch (columnIndex) { - case 0: - if (element instanceof ResourceType) { - return ((ResourceType)element).getDisplayName(); - } else if (element instanceof ResourceItem) { - return ((ResourceItem)element).getName(); - } else if (element instanceof ResourceFile) { - return ((ResourceFile)element).getFolder().getConfiguration().toDisplayString(); - } - break; - case 1: - if (element instanceof ConfigurableResourceItem) { - ConfigurableResourceItem item = (ConfigurableResourceItem)element; - int count = item.getAlternateCount(); - if (count > 0) { - if (item.hasDefault()) { - count++; - } - return String.format("%1$d version(s)", count); - } - } else if (element instanceof IIdResourceItem) { - IIdResourceItem idResource = (IIdResourceItem)element; - if (idResource.isDeclaredInline()) { - return "Declared inline"; - } - } - return null; - } - return null; - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlContentAssist.java deleted file mode 100644 index f28b523..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlContentAssist.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.xml; - -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.editors.AndroidContentAssist; - -/** - * Content Assist Processor for /res/xml XML files - */ -class XmlContentAssist extends AndroidContentAssist { - - /** - * Constructor for LayoutContentAssist - */ - public XmlContentAssist() { - super(AndroidTargetData.DESCRIPTOR_XML); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java deleted file mode 100644 index d7f6119..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlEditor.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.xml; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.sdk.Sdk; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.AndroidEditor; -import com.android.ide.eclipse.editors.FirstElementParser; -import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; -import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.SdkConstants; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.part.FileEditorInput; -import org.w3c.dom.Document; - -/** - * Multi-page form editor for /res/xml XML files. - */ -public class XmlEditor extends AndroidEditor { - - public static final String ID = AndroidConstants.EDITORS_NAMESPACE + ".xml.XmlEditor"; //$NON-NLS-1$ - - /** Root node of the UI element hierarchy */ - private UiDocumentNode mUiRootNode; - - /** - * Creates the form editor for resources XML files. - */ - public XmlEditor() { - super(); - } - - /** - * Returns the root node of the UI element hierarchy, which here - * is the document node. - */ - @Override - public UiDocumentNode getUiRootNode() { - return mUiRootNode; - } - - // ---- Static ---- - - /** - * Indicates if this is a file that this {@link XmlEditor} can handle. - * <p/> - * The {@link XmlEditor} can handle XML files that have a <searchable> or - * <Preferences> root XML element with the adequate xmlns:android attribute. - * - * @return True if the {@link XmlEditor} can handle that file. - */ - public static boolean canHandleFile(IFile file) { - // we need the target of the file's project to access the descriptors. - IProject project = file.getProject(); - IAndroidTarget target = Sdk.getCurrent().getTarget(project); - if (target != null) { - AndroidTargetData data = Sdk.getCurrent().getTargetData(target); - - FirstElementParser.Result result = FirstElementParser.parse( - file.getLocation().toOSString(), - SdkConstants.NS_RESOURCES); - - if (result != null) { - String name = result.getElement(); - if (name != null && result.getXmlnsPrefix() != null) { - DocumentDescriptor desc = data.getXmlDescriptors().getDescriptor(); - for (ElementDescriptor elem : desc.getChildren()) { - if (elem.getXmlName().equals(name)) { - // This is an element that this document can handle - return true; - } - } - } - } - } - - return false; - } - - // ---- Base Class Overrides ---- - - /** - * Returns whether the "save as" operation is supported by this editor. - * <p/> - * Save-As is a valid operation for the ManifestEditor since it acts on a - * single source file. - * - * @see IEditorPart - */ - @Override - public boolean isSaveAsAllowed() { - return true; - } - - /** - * Create the various form pages. - */ - @Override - protected void createFormPages() { - try { - addPage(new XmlTreePage(this)); - } catch (PartInitException e) { - AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$ - } - - } - - /* (non-java doc) - * Change the tab/title name to include the project name. - */ - @Override - protected void setInput(IEditorInput input) { - super.setInput(input); - if (input instanceof FileEditorInput) { - FileEditorInput fileInput = (FileEditorInput) input; - IFile file = fileInput.getFile(); - setPartName(String.format("%1$s", file.getName())); - } - } - - /** - * Processes the new XML Model, which XML root node is given. - * - * @param xml_doc The XML document, if available, or null if none exists. - */ - @Override - protected void xmlModelChanged(Document xml_doc) { - // init the ui root on demand - initUiRootNode(false /*force*/); - - mUiRootNode.loadFromXmlNode(xml_doc); - - super.xmlModelChanged(xml_doc); - } - - /** - * Creates the initial UI Root Node, including the known mandatory elements. - * @param force if true, a new UiRootNode is recreated even if it already exists. - */ - @Override - protected void initUiRootNode(boolean force) { - // The root UI node is always created, even if there's no corresponding XML node. - if (mUiRootNode == null || force) { - Document doc = null; - if (mUiRootNode != null) { - doc = mUiRootNode.getXmlDocument(); - } - - // get the target data from the opened file (and its project) - AndroidTargetData data = getTargetData(); - - DocumentDescriptor desc; - if (data == null) { - desc = new DocumentDescriptor("temp", null /*children*/); - } else { - desc = data.getXmlDescriptors().getDescriptor(); - } - - mUiRootNode = (UiDocumentNode) desc.createUiNode(); - mUiRootNode.setEditor(this); - - onDescriptorsChanged(doc); - } - } - - // ---- Local Methods ---- - - /** - * Reloads the UI manifest node from the XML, and calls the pages to update. - */ - private void onDescriptorsChanged(Document document) { - if (document != null) { - mUiRootNode.loadFromXmlNode(document); - } else { - mUiRootNode.reloadFromXmlNode(mUiRootNode.getXmlNode()); - } - } - -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlSourceViewerConfig.java deleted file mode 100644 index d25c812..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlSourceViewerConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.xml; - - -import com.android.ide.eclipse.editors.AndroidSourceViewerConfig; - -/** - * Source Viewer Configuration that calls in XmlContentAssist. - */ -public class XmlSourceViewerConfig extends AndroidSourceViewerConfig { - - public XmlSourceViewerConfig() { - super(new XmlContentAssist()); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlTreePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlTreePage.java deleted file mode 100644 index 91ce6dd..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/XmlTreePage.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.xml; - -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.editors.ui.tree.UiTreeBlock; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; - -/** - * Page for the xml form editor. - */ -public final class XmlTreePage extends FormPage { - /** Page id used for switching tabs programmatically */ - public final static String PAGE_ID = "xml_tree_page"; //$NON-NLS-1$ - - /** Container editor */ - XmlEditor mEditor; - - public XmlTreePage(XmlEditor editor) { - super(editor, PAGE_ID, "Structure"); // tab's label, keep it short - mEditor = editor; - } - - /** - * Creates the content in the form hosted in this page. - * - * @param managedForm the form hosted in this page. - */ - @Override - protected void createFormContent(IManagedForm managedForm) { - super.createFormContent(managedForm); - ScrolledForm form = managedForm.getForm(); - form.setText("Android Xml"); - form.setImage(AdtPlugin.getAndroidLogo()); - - UiElementNode rootNode = mEditor.getUiRootNode(); - UiTreeBlock block = new UiTreeBlock(mEditor, rootNode, - true /* autoCreateRoot */, - null /* no element filters */, - "Xml Elements", - "List of all xml elements in this XML file."); - block.createContent(managedForm); - } -} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java deleted file mode 100644 index fa1370f..0000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2008 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.editors.xml.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo; -import com.android.ide.eclipse.common.resources.ViewClassInfo; -import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo; -import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; -import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; -import com.android.ide.eclipse.editors.descriptors.ElementDescriptor; -import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider; -import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor; -import com.android.ide.eclipse.editors.descriptors.XmlnsAttributeDescriptor; -import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor; -import com.android.sdklib.SdkConstants; - -import java.util.ArrayList; -import java.util.Map; - - -/** - * Description of the /res/xml structure. - * Currently supports the <searchable> and <preferences> root nodes. - */ -public final class XmlDescriptors implements IDescriptorProvider { - - // Public attributes names, attributes descriptors and elements descriptors referenced - // elsewhere. - public static final String PREF_KEY_ATTR = "key"; //$NON-NLS-1$ - - /** The root document descriptor for both searchable and preferences. */ - private DocumentDescriptor mDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$ - - /** The root document descriptor for searchable. */ - private DocumentDescriptor mSearchDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$ - - /** The root document descriptor for preferences. */ - private DocumentDescriptor mPrefDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$ - - /** @return the root descriptor for both searchable and preferences. */ - public DocumentDescriptor getDescriptor() { - return mDescriptor; - } - - public ElementDescriptor[] getRootElementDescriptors() { - return mDescriptor.getChildren(); - } - - /** @return the root descriptor for searchable. */ - public DocumentDescriptor getSearchableDescriptor() { - return mSearchDescriptor; - } - - /** @return the root descriptor for preferences. */ - public DocumentDescriptor getPreferencesDescriptor() { - return mPrefDescriptor; - } - - public IDescriptorProvider getSearchableProvider() { - return new IDescriptorProvider() { - public ElementDescriptor getDescriptor() { - return mSearchDescriptor; - } - - public ElementDescriptor[] getRootElementDescriptors() { - return mSearchDescriptor.getChildren(); - } - }; - } - - public IDescriptorProvider getPreferencesProvider() { - return new IDescriptorProvider() { - public ElementDescriptor getDescriptor() { - return mPrefDescriptor; - } - - public ElementDescriptor[] getRootElementDescriptors() { - return mPrefDescriptor.getChildren(); - } - }; - } - - /** - * Updates the document descriptor. - * <p/> - * It first computes the new children of the descriptor and then updates them - * all at once. - * - * @param searchableStyleMap The map style=>attributes for <searchable> from the attrs.xml file - * @param prefs The list of non-group preference descriptions - * @param prefGroups The list of preference group descriptions - */ - public synchronized void updateDescriptors( - Map<String, DeclareStyleableInfo> searchableStyleMap, - ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) { - - XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor( - "android", //$NON-NLS-1$ - SdkConstants.NS_RESOURCES); - - ElementDescriptor searchable = createSearchable(searchableStyleMap, xmlns); - ElementDescriptor preferences = createPreference(prefs, prefGroups, xmlns); - ArrayList<ElementDescriptor> list = new ArrayList<ElementDescriptor>(); - if (searchable != null) { - list.add(searchable); - mSearchDescriptor.setChildren(new ElementDescriptor[]{ searchable }); - } - if (preferences != null) { - list.add(preferences); - mPrefDescriptor.setChildren(new ElementDescriptor[]{ preferences }); - } - - if (list.size() > 0) { - mDescriptor.setChildren(list.toArray(new ElementDescriptor[list.size()])); - } - } - - //------------------------- - // Creation of <searchable> - //------------------------- - - /** - * Returns the new ElementDescriptor for <searchable> - */ - private ElementDescriptor createSearchable( - Map<String, DeclareStyleableInfo> searchableStyleMap, - XmlnsAttributeDescriptor xmlns) { - - ElementDescriptor action_key = createElement(searchableStyleMap, - "SearchableActionKey", //$NON-NLS-1$ styleName - "actionkey", //$NON-NLS-1$ xmlName - "Action Key", // uiName - null, // sdk url - null, // extraAttribute - null, // childrenElements - false /* mandatory */ ); - - ElementDescriptor searchable = createElement(searchableStyleMap, - "Searchable", //$NON-NLS-1$ styleName - "searchable", //$NON-NLS-1$ xmlName - "Searchable", // uiName - null, // sdk url - xmlns, // extraAttribute - new ElementDescriptor[] { action_key }, // childrenElements - false /* mandatory */ ); - return searchable; - } - - /** - * Returns a new ElementDescriptor constructed from the information given here - * and the javadoc & attributes extracted from the style map if any. - */ - private ElementDescriptor createElement( - Map<String, DeclareStyleableInfo> styleMap, String styleName, - String xmlName, String uiName, String sdkUrl, - AttributeDescriptor extraAttribute, - ElementDescriptor[] childrenElements, boolean mandatory) { - - ElementDescriptor element = new ElementDescriptor(xmlName, uiName, null, sdkUrl, - null, childrenElements, mandatory); - - return updateElement(element, styleMap, styleName, extraAttribute); - } - - /** - * Updates an ElementDescriptor with the javadoc & attributes extracted from the style - * map if any. - */ - private ElementDescriptor updateElement(ElementDescriptor element, - Map<String, DeclareStyleableInfo> styleMap, - String styleName, - AttributeDescriptor extraAttribute) { - ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>(); - - DeclareStyleableInfo style = styleMap != null ? styleMap.get(styleName) : null; - if (style != null) { - DescriptorsUtils.appendAttributes(descs, - null, // elementName - SdkConstants.NS_RESOURCES, - style.getAttributes(), - null, // requiredAttributes - null); // overrides - element.setTooltip(style.getJavaDoc()); - } - - if (extraAttribute != null) { - descs.add(extraAttribute); - } - - element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()])); - return element; - } - - //-------------------------- - // Creation of <Preferences> - //-------------------------- - - /** - * Returns the new ElementDescriptor for <Preferences> - */ - private ElementDescriptor createPreference(ViewClassInfo[] prefs, - ViewClassInfo[] prefGroups, XmlnsAttributeDescriptor xmlns) { - - ArrayList<ElementDescriptor> newPrefs = new ArrayList<ElementDescriptor>(); - if (prefs != null) { - for (ViewClassInfo info : prefs) { - ElementDescriptor desc = convertPref(info); - newPrefs.add(desc); - } - } - - ElementDescriptor topPreferences = null; - - ArrayList<ElementDescriptor> newGroups = new ArrayList<ElementDescriptor>(); - if (prefGroups != null) { - for (ViewClassInfo info : prefGroups) { - ElementDescriptor desc = convertPref(info); - newGroups.add(desc); - - if (info.getCanonicalClassName() == AndroidConstants.CLASS_PREFERENCES) { - topPreferences = desc; - } - } - } - - ArrayList<ElementDescriptor> everything = new ArrayList<ElementDescriptor>(); - everything.addAll(newGroups); - everything.addAll(newPrefs); - ElementDescriptor[] newArray = everything.toArray(new ElementDescriptor[everything.size()]); - - // Link all groups to everything else here.. recursively - for (ElementDescriptor layoutDesc : newGroups) { - layoutDesc.setChildren(newArray); - } - - // The "top" element to be returned corresponds to the class "Preferences". - // Its descriptor has already been created. However the root one also needs - // the hidden xmlns:android definition.. - if (topPreferences != null) { - AttributeDescriptor[] attrs = topPreferences.getAttributes(); - AttributeDescriptor[] newAttrs = new AttributeDescriptor[attrs.length + 1]; - System.arraycopy(attrs, 0, newAttrs, 0, attrs.length); - newAttrs[attrs.length] = xmlns; - return new ElementDescriptor( - topPreferences.getXmlName(), - topPreferences.getUiName(), - topPreferences.getTooltip(), - topPreferences.getSdkUrl(), - newAttrs, - topPreferences.getChildren(), - false /* mandatory */); - } else { - return null; - } - } - - /** - * Creates an element descriptor from a given {@link ViewClassInfo}. - */ - private ElementDescriptor convertPref(ViewClassInfo info) { - String xml_name = info.getShortClassName(); - String tooltip = info.getJavaDoc(); - - // Process all Preference attributes - ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>(); - DescriptorsUtils.appendAttributes(attributes, - null, // elementName - SdkConstants.NS_RESOURCES, - info.getAttributes(), - null, // requiredAttributes - null); // overrides - - for (ViewClassInfo link = info.getSuperClass(); - link != null; - link = link.getSuperClass()) { - AttributeInfo[] attrList = link.getAttributes(); - if (attrList.length > 0) { - attributes.add(new SeparatorAttributeDescriptor( - String.format("Attributes from %1$s", link.getShortClassName()))); - DescriptorsUtils.appendAttributes(attributes, - null, // elementName - SdkConstants.NS_RESOURCES, - attrList, - null, // requiredAttributes - null); // overrides - } - } - - return new ViewElementDescriptor(xml_name, - xml_name, // ui_name - info.getCanonicalClassName(), - tooltip, - null, // sdk_url - attributes.toArray(new AttributeDescriptor[attributes.size()]), - null, - null, // children - false /* mandatory */); - } -} |