1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.ide.eclipse.adt.internal.welcome; 17 18 import com.android.ide.eclipse.adt.AdtPlugin; 19 import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; 20 21 import org.eclipse.jface.dialogs.IMessageProvider; 22 import org.eclipse.jface.wizard.WizardPage; 23 import org.eclipse.swt.SWT; 24 import org.eclipse.swt.events.ModifyEvent; 25 import org.eclipse.swt.events.ModifyListener; 26 import org.eclipse.swt.events.SelectionEvent; 27 import org.eclipse.swt.events.SelectionListener; 28 import org.eclipse.swt.layout.GridData; 29 import org.eclipse.swt.layout.GridLayout; 30 import org.eclipse.swt.widgets.Button; 31 import org.eclipse.swt.widgets.Composite; 32 import org.eclipse.swt.widgets.DirectoryDialog; 33 import org.eclipse.swt.widgets.Label; 34 import org.eclipse.swt.widgets.Text; 35 36 import java.io.File; 37 import java.util.concurrent.atomic.AtomicReference; 38 39 /** Main page shown in the {@link WelcomeWizard} */ 40 public class WelcomeWizardPage extends WizardPage implements ModifyListener, SelectionListener { 41 private Text mExistingDirText; 42 private Button mExistingDirButton; 43 private Button mInstallLatestCheckbox; 44 private Button mInstallCommonCheckbox; 45 private Button mInstallNewRadio; 46 private Button mUseExistingRadio; 47 private Text mNewDirText; 48 private Button mNewDirButton; 49 50 /** 51 * Create the wizard. 52 */ WelcomeWizardPage()53 public WelcomeWizardPage() { 54 super("welcomePage"); 55 setTitle("Welcome to Android Development"); 56 setDescription("Configure SDK"); 57 } 58 59 /** 60 * Create contents of the wizard. 61 * @param parent parent widget to add page to 62 */ 63 @Override 64 @SuppressWarnings("unused") // SWT constructors have side effects so "new Label" is not unused createControl(Composite parent)65 public void createControl(Composite parent) { 66 Composite container = new Composite(parent, SWT.NULL); 67 68 setControl(container); 69 container.setLayout(new GridLayout(4, false)); 70 71 Label overviewLabel = new Label(container, SWT.WRAP | SWT.SHADOW_NONE); 72 GridData gdOverviewLabel = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1); 73 gdOverviewLabel.widthHint = 580; 74 overviewLabel.setLayoutData(gdOverviewLabel); 75 overviewLabel.setText("To develop for Android, you need an Android SDK, and at least one version of the Android APIs to compile against. You may also want additional versions of Android to test with."); 76 77 Label spacing = new Label(container, SWT.NONE); 78 spacing.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 79 80 mInstallNewRadio = new Button(container, SWT.RADIO); 81 mInstallNewRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 82 mInstallNewRadio.setSelection(true); 83 mInstallNewRadio.setText("Install new SDK"); 84 mInstallNewRadio.addSelectionListener(this); 85 86 Label indentLabel = new Label(container, SWT.NONE); 87 GridData gdIndentLabel = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); 88 gdIndentLabel.widthHint = 20; 89 indentLabel.setLayoutData(gdIndentLabel); 90 91 mInstallLatestCheckbox = new Button(container, SWT.CHECK); 92 mInstallLatestCheckbox.setSelection(true); 93 mInstallLatestCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 94 1)); 95 mInstallLatestCheckbox.setText("Install the latest available version of Android APIs (supports all the latest features)"); 96 mInstallLatestCheckbox.addSelectionListener(this); 97 98 new Label(container, SWT.NONE); 99 mInstallCommonCheckbox = new Button(container, SWT.CHECK); 100 mInstallCommonCheckbox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 101 1)); 102 mInstallCommonCheckbox.setText("Install Android 2.2, a version which is supported by ~96% phones and tablets"); 103 mInstallCommonCheckbox.addSelectionListener(this); 104 105 new Label(container, SWT.NONE); 106 Label addHintLabel = new Label(container, SWT.NONE); 107 addHintLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); 108 addHintLabel.setText(" (You can add additional platforms using the SDK Manager.)"); 109 110 new Label(container, SWT.NONE); 111 Label targetLabel = new Label(container, SWT.NONE); 112 targetLabel.setText("Target Location:"); 113 114 mNewDirText = new Text(container, SWT.BORDER); 115 mNewDirText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 116 String defaultPath = System.getProperty("user.home") + File.separator + "android-sdks"; //$NON-NLS-1$ 117 mNewDirText.setText(defaultPath); 118 mNewDirText.addModifyListener(this); 119 120 mNewDirButton = new Button(container, SWT.FLAT); 121 mNewDirButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 122 mNewDirButton.setText("Browse..."); 123 mNewDirButton.addSelectionListener(this); 124 125 Label spacing2 = new Label(container, SWT.NONE); 126 spacing2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 127 128 mUseExistingRadio = new Button(container, SWT.RADIO); 129 mUseExistingRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 130 mUseExistingRadio.setText("Use existing SDKs"); 131 mUseExistingRadio.addSelectionListener(this); 132 133 new Label(container, SWT.NONE); 134 Label installationLabel = new Label(container, SWT.NONE); 135 installationLabel.setText("Existing Location:"); 136 137 mExistingDirText = new Text(container, SWT.BORDER); 138 mExistingDirText.setEnabled(false); 139 mExistingDirText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 140 mExistingDirText.addModifyListener(this); 141 142 mExistingDirButton = new Button(container, SWT.FLAT); 143 mExistingDirButton.setEnabled(false); 144 mExistingDirButton.setText("Browse..."); 145 mExistingDirButton.addSelectionListener(this); 146 } 147 isCreateNew()148 boolean isCreateNew() { 149 return mInstallNewRadio.getSelection(); 150 } 151 isInstallLatest()152 boolean isInstallLatest() { 153 return mInstallLatestCheckbox.getSelection(); 154 } 155 isInstallCommon()156 boolean isInstallCommon() { 157 return mInstallCommonCheckbox.getSelection(); 158 } 159 getPath()160 File getPath() { 161 Text text = isCreateNew() ? mNewDirText : mExistingDirText; 162 return new File(text.getText()); 163 } 164 165 @Override widgetSelected(SelectionEvent e)166 public void widgetSelected(SelectionEvent e) { 167 Object source = e.getSource(); 168 169 if (source == mExistingDirButton) { 170 DirectoryDialog dialog = new DirectoryDialog(mExistingDirButton.getShell(), SWT.OPEN); 171 String file = dialog.open(); 172 String path = mExistingDirText.getText().trim(); 173 if (path.length() > 0) { 174 // TODO: Shouldn't this be done before the open() call? 175 dialog.setFilterPath(path); 176 } 177 if (file != null) { 178 mExistingDirText.setText(file); 179 } 180 } else if (source == mNewDirButton) { 181 DirectoryDialog dialog = new DirectoryDialog(mNewDirButton.getShell(), SWT.OPEN); 182 String path = mNewDirText.getText().trim(); 183 if (path.length() > 0) { 184 dialog.setFilterPath(path); 185 } 186 String file = dialog.open(); 187 if (file != null) { 188 mNewDirText.setText(file); 189 } 190 } else if (source == mInstallNewRadio) { 191 mExistingDirButton.setEnabled(false); 192 mExistingDirText.setEnabled(false); 193 mNewDirButton.setEnabled(true); 194 mNewDirText.setEnabled(true); 195 } else if (source == mUseExistingRadio) { 196 mExistingDirButton.setEnabled(true); 197 mExistingDirText.setEnabled(true); 198 mNewDirButton.setEnabled(false); 199 mNewDirText.setEnabled(false); 200 } 201 202 validatePage(); 203 } 204 205 @Override widgetDefaultSelected(SelectionEvent e)206 public void widgetDefaultSelected(SelectionEvent e) { 207 } 208 209 @Override modifyText(ModifyEvent e)210 public void modifyText(ModifyEvent e) { 211 validatePage(); 212 } 213 validatePage()214 private void validatePage() { 215 String error = null; 216 String warning = null; 217 218 if (isCreateNew()) { 219 // Make sure that the target installation directory is empty or doesn't exist 220 // (and that it can be created) 221 String path = mNewDirText.getText().trim(); 222 if (path.length() == 0) { 223 error = "Please enter a new directory to install the SDK into"; 224 } else { 225 File file = new File(path); 226 if (file.exists()) { 227 if (file.isDirectory()) { 228 if (!file.canWrite()) { 229 error = "Missing write permission in target directory"; 230 } 231 File[] children = file.listFiles(); 232 if (children != null && children.length > 0) { 233 warning = "The directory is not empty"; 234 } 235 } else { 236 error = "The target must be a directory"; 237 } 238 } else { 239 File parent = file.getParentFile(); 240 if (parent == null || !parent.exists()) { 241 error = "The parent directory does not exist"; 242 } else if (!parent.canWrite()) { 243 error = "No write permission in parent directory"; 244 } 245 } 246 } 247 248 if (error == null && !mInstallLatestCheckbox.getSelection() 249 && !mInstallCommonCheckbox.getSelection()) { 250 error = "You must choose at least one Android version to install"; 251 } 252 } else { 253 // Make sure that the existing installation directory exists and is valid 254 String path = mExistingDirText.getText().trim(); 255 if (path.length() == 0) { 256 error = "Please enter an existing SDK installation directory"; 257 } else { 258 File file = new File(path); 259 if (!file.exists()) { 260 error = "The chosen installation directory does not exist"; 261 } else { 262 final AtomicReference<String> errorReference = new AtomicReference<String>(); 263 final AtomicReference<String> warningReference = new AtomicReference<String>(); 264 AdtPlugin.getDefault().checkSdkLocationAndId(path, 265 new AdtPlugin.CheckSdkErrorHandler() { 266 @Override 267 public boolean handleError( 268 CheckSdkErrorHandler.Solution solution, 269 String message) { 270 message = message.replaceAll("\n", " "); //$NON-NLS-1$ //$NON-NLS-2$ 271 errorReference.set(message); 272 return false; // Apply/OK must be disabled 273 } 274 275 @Override 276 public boolean handleWarning( 277 CheckSdkErrorHandler.Solution solution, 278 String message) { 279 message = message.replaceAll("\n", " "); //$NON-NLS-1$ //$NON-NLS-2$ 280 warningReference.set(message); 281 return true; // Apply/OK must be enabled 282 } 283 }); 284 error = errorReference.get(); 285 if (warning == null) { 286 warning = warningReference.get(); 287 } 288 } 289 } 290 } 291 292 setPageComplete(error == null); 293 if (error != null) { 294 setMessage(error, IMessageProvider.ERROR); 295 } else if (warning != null) { 296 setMessage(warning, IMessageProvider.WARNING); 297 } else { 298 setErrorMessage(null); 299 setMessage(null); 300 } 301 } 302 } 303