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