1 /* 2 * Copyright (C) 2012 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.wizards.templates; 17 18 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.CATEGORY_ACTIVITIES; 19 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.CATEGORY_OTHER; 20 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.IS_LAUNCHER; 21 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_PADDING; 22 import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_WIDTH; 23 24 import com.android.ide.eclipse.adt.AdtPlugin; 25 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl; 26 import com.google.common.collect.Lists; 27 import com.google.common.io.Files; 28 29 import org.eclipse.core.runtime.IStatus; 30 import org.eclipse.core.runtime.Status; 31 import org.eclipse.jface.dialogs.IMessageProvider; 32 import org.eclipse.jface.resource.JFaceResources; 33 import org.eclipse.jface.wizard.WizardPage; 34 import org.eclipse.swt.SWT; 35 import org.eclipse.swt.events.SelectionEvent; 36 import org.eclipse.swt.events.SelectionListener; 37 import org.eclipse.swt.graphics.Font; 38 import org.eclipse.swt.graphics.Image; 39 import org.eclipse.swt.layout.GridData; 40 import org.eclipse.swt.layout.GridLayout; 41 import org.eclipse.swt.widgets.Button; 42 import org.eclipse.swt.widgets.Composite; 43 import org.eclipse.swt.widgets.Label; 44 import org.eclipse.swt.widgets.List; 45 46 import java.io.ByteArrayInputStream; 47 import java.io.File; 48 import java.io.IOException; 49 import java.util.ArrayList; 50 51 class ActivityPage extends WizardPage implements SelectionListener { 52 private final NewProjectWizardState mValues; 53 private List mList; 54 private Button mCreateToggle; 55 private java.util.List<File> mTemplates; 56 57 private boolean mIgnore; 58 private boolean mShown; 59 private ImageControl mPreview; 60 private Image mPreviewImage; 61 private boolean mDisposePreviewImage; 62 private Label mHeading; 63 private Label mDescription; 64 private boolean mOnlyActivities; 65 private boolean mAskCreate; 66 private boolean mLauncherActivitiesOnly; 67 68 /** 69 * Create the wizard. 70 */ ActivityPage(NewProjectWizardState values, boolean onlyActivities, boolean askCreate)71 ActivityPage(NewProjectWizardState values, boolean onlyActivities, boolean askCreate) { 72 super("activityPage"); //$NON-NLS-1$ 73 mValues = values; 74 mOnlyActivities = onlyActivities; 75 mAskCreate = askCreate; 76 77 if (onlyActivities) { 78 setTitle("Create Activity"); 79 } else { 80 setTitle("Create Android Object"); 81 } 82 if (onlyActivities && askCreate) { 83 setDescription( 84 "Select whether to create an activity, and if so, what kind of activity."); 85 } else { 86 setDescription("Select which template to use"); 87 } 88 } 89 90 /** Sets whether the activity page should only offer launcher activities */ setLauncherActivitiesOnly(boolean launcherActivitiesOnly)91 void setLauncherActivitiesOnly(boolean launcherActivitiesOnly) { 92 mLauncherActivitiesOnly = launcherActivitiesOnly; 93 } 94 95 @Override createControl(Composite parent)96 public void createControl(Composite parent) { 97 Composite container = new Composite(parent, SWT.NULL); 98 setControl(container); 99 } 100 101 @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused onEnter()102 private void onEnter() { 103 Composite container = (Composite) getControl(); 104 container.setLayout(new GridLayout(3, false)); 105 106 if (mAskCreate) { 107 mCreateToggle = new Button(container, SWT.CHECK); 108 mCreateToggle.setSelection(true); 109 mCreateToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); 110 mCreateToggle.setText("Create Activity"); 111 mCreateToggle.addSelectionListener(this); 112 } 113 114 mList = new List(container, SWT.BORDER | SWT.V_SCROLL); 115 mList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); 116 117 118 TemplateManager manager = mValues.template.getManager(); 119 java.util.List<File> templates = manager.getTemplates(CATEGORY_ACTIVITIES); 120 121 if (!mOnlyActivities) { 122 templates.addAll(manager.getTemplates(CATEGORY_OTHER)); 123 } 124 java.util.List<String> names = new ArrayList<String>(templates.size()); 125 File current = mValues.activityValues.getTemplateLocation(); 126 mTemplates = Lists.newArrayListWithExpectedSize(templates.size()); 127 int index = -1; 128 for (int i = 0, n = templates.size(); i < n; i++) { 129 File template = templates.get(i); 130 TemplateMetadata metadata = manager.getTemplate(template); 131 if (metadata == null) { 132 continue; 133 } 134 if (mLauncherActivitiesOnly) { 135 Parameter parameter = metadata.getParameter(IS_LAUNCHER); 136 if (parameter == null) { 137 continue; 138 } 139 } 140 mTemplates.add(template); 141 names.add(metadata.getTitle()); 142 if (template.equals(current)) { 143 index = names.size(); 144 } 145 } 146 String[] items = names.toArray(new String[names.size()]); 147 mList.setItems(items); 148 if (index == -1 && !mTemplates.isEmpty()) { 149 mValues.activityValues.setTemplateLocation(mTemplates.get(0)); 150 index = 0; 151 } 152 if (index >= 0) { 153 mList.setSelection(index); 154 mList.addSelectionListener(this); 155 } 156 157 // Preview 158 mPreview = new ImageControl(container, SWT.NONE, null); 159 mPreview.setDisposeImage(false); // Handled manually in this class 160 GridData gd_mImage = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1); 161 gd_mImage.widthHint = PREVIEW_WIDTH + 2 * PREVIEW_PADDING; 162 mPreview.setLayoutData(gd_mImage); 163 new Label(container, SWT.NONE); 164 165 mHeading = new Label(container, SWT.NONE); 166 mHeading.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 167 new Label(container, SWT.NONE); 168 169 mDescription = new Label(container, SWT.WRAP); 170 mDescription.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); 171 172 Font font = JFaceResources.getFontRegistry().getBold(JFaceResources.BANNER_FONT); 173 if (font != null) { 174 mHeading.setFont(font); 175 } 176 177 updatePreview(); 178 } 179 updatePreview()180 private void updatePreview() { 181 Image oldImage = mPreviewImage; 182 boolean dispose = mDisposePreviewImage; 183 mPreviewImage = null; 184 185 String title = ""; 186 String description = ""; 187 TemplateHandler handler = mValues.activityValues.getTemplateHandler(); 188 TemplateMetadata template = handler.getTemplate(); 189 if (template != null) { 190 String thumb = template.getThumbnailPath(); 191 if (thumb != null && !thumb.isEmpty()) { 192 File file = new File(mValues.activityValues.getTemplateLocation(), 193 thumb.replace('/', File.separatorChar)); 194 if (file != null) { 195 try { 196 byte[] bytes = Files.toByteArray(file); 197 ByteArrayInputStream input = new ByteArrayInputStream(bytes); 198 mPreviewImage = new Image(getControl().getDisplay(), input); 199 mDisposePreviewImage = true; 200 input.close(); 201 } catch (IOException e) { 202 AdtPlugin.log(e, null); 203 } 204 } 205 } else { 206 // Fallback icon 207 mDisposePreviewImage = false; 208 mPreviewImage = TemplateMetadata.getDefaultTemplateIcon(); 209 } 210 title = template.getTitle(); 211 description = template.getDescription(); 212 } 213 214 mHeading.setText(title); 215 mDescription.setText(description); 216 mPreview.setImage(mPreviewImage); 217 mPreview.fitToWidth(PREVIEW_WIDTH); 218 219 if (oldImage != null && dispose) { 220 oldImage.dispose(); 221 } 222 223 Composite parent = (Composite) getControl(); 224 parent.layout(true, true); 225 parent.redraw(); 226 } 227 228 @Override dispose()229 public void dispose() { 230 super.dispose(); 231 232 if (mPreviewImage != null && mDisposePreviewImage) { 233 mDisposePreviewImage = false; 234 mPreviewImage.dispose(); 235 mPreviewImage = null; 236 } 237 } 238 239 @Override setVisible(boolean visible)240 public void setVisible(boolean visible) { 241 if (visible && !mShown) { 242 onEnter(); 243 } 244 245 super.setVisible(visible); 246 247 if (visible) { 248 mShown = true; 249 if (mAskCreate) { 250 try { 251 mIgnore = true; 252 mCreateToggle.setSelection(mValues.createActivity); 253 } finally { 254 mIgnore = false; 255 } 256 } 257 } 258 259 validatePage(); 260 } 261 262 validatePage()263 private void validatePage() { 264 IStatus status = null; 265 266 if (mValues.createActivity) { 267 if (mList.getSelectionCount() < 1) { 268 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, 269 "Select an activity type"); 270 } else { 271 TemplateHandler templateHandler = mValues.activityValues.getTemplateHandler(); 272 status = templateHandler.validateTemplate(mValues.minSdkLevel, 273 mValues.getBuildApi()); 274 } 275 } 276 277 setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); 278 if (status != null) { 279 setMessage(status.getMessage(), 280 status.getSeverity() == IStatus.ERROR 281 ? IMessageProvider.ERROR : IMessageProvider.WARNING); 282 } else { 283 setErrorMessage(null); 284 setMessage(null); 285 } 286 } 287 288 @Override isPageComplete()289 public boolean isPageComplete() { 290 // Ensure that the Finish button isn't enabled until 291 // the user has reached and completed this page 292 if (!mShown && mValues.createActivity) { 293 return false; 294 } 295 296 return super.isPageComplete(); 297 } 298 299 // ---- Implements SelectionListener ---- 300 301 @Override widgetSelected(SelectionEvent e)302 public void widgetSelected(SelectionEvent e) { 303 if (mIgnore) { 304 return; 305 } 306 307 Object source = e.getSource(); 308 if (source == mCreateToggle) { 309 mValues.createActivity = mCreateToggle.getSelection(); 310 mList.setEnabled(mValues.createActivity); 311 } else if (source == mList) { 312 int index = mList.getSelectionIndex(); 313 if (index >= 0 && index < mTemplates.size()) { 314 File template = mTemplates.get(index); 315 mValues.activityValues.setTemplateLocation(template); 316 updatePreview(); 317 } 318 } 319 320 validatePage(); 321 } 322 323 @Override widgetDefaultSelected(SelectionEvent e)324 public void widgetDefaultSelected(SelectionEvent e) { 325 } 326 } 327