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 
17 package com.android.ide.eclipse.adt.internal.assetstudio;
18 
19 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.DEFAULT_LAUNCHER_ICON;
20 import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
21 
22 import com.android.annotations.NonNull;
23 import com.android.annotations.Nullable;
24 import com.android.assetstudiolib.ActionBarIconGenerator;
25 import com.android.assetstudiolib.GraphicGenerator;
26 import com.android.assetstudiolib.GraphicGenerator.Shape;
27 import com.android.assetstudiolib.LauncherIconGenerator;
28 import com.android.assetstudiolib.MenuIconGenerator;
29 import com.android.assetstudiolib.NotificationIconGenerator;
30 import com.android.assetstudiolib.TabIconGenerator;
31 import com.android.assetstudiolib.TextRenderUtil;
32 import com.android.assetstudiolib.Util;
33 import com.android.ide.eclipse.adt.AdtPlugin;
34 import com.android.ide.eclipse.adt.AdtUtils;
35 import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState.SourceType;
36 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl;
37 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils;
38 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SwtUtils;
39 import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
40 import com.android.utils.Pair;
41 
42 import org.eclipse.core.resources.IFile;
43 import org.eclipse.core.resources.IProject;
44 import org.eclipse.core.resources.IResource;
45 import org.eclipse.core.resources.IWorkspaceRoot;
46 import org.eclipse.core.resources.ResourcesPlugin;
47 import org.eclipse.core.runtime.CoreException;
48 import org.eclipse.core.runtime.IPath;
49 import org.eclipse.core.runtime.IStatus;
50 import org.eclipse.core.runtime.NullProgressMonitor;
51 import org.eclipse.core.runtime.Path;
52 import org.eclipse.jface.dialogs.IMessageProvider;
53 import org.eclipse.jface.dialogs.MessageDialog;
54 import org.eclipse.jface.wizard.WizardPage;
55 import org.eclipse.swt.SWT;
56 import org.eclipse.swt.custom.ScrolledComposite;
57 import org.eclipse.swt.custom.StackLayout;
58 import org.eclipse.swt.events.ModifyEvent;
59 import org.eclipse.swt.events.ModifyListener;
60 import org.eclipse.swt.events.MouseAdapter;
61 import org.eclipse.swt.events.MouseEvent;
62 import org.eclipse.swt.events.SelectionEvent;
63 import org.eclipse.swt.events.SelectionListener;
64 import org.eclipse.swt.graphics.Color;
65 import org.eclipse.swt.graphics.Font;
66 import org.eclipse.swt.graphics.FontData;
67 import org.eclipse.swt.graphics.Image;
68 import org.eclipse.swt.graphics.RGB;
69 import org.eclipse.swt.layout.GridData;
70 import org.eclipse.swt.layout.GridLayout;
71 import org.eclipse.swt.layout.RowData;
72 import org.eclipse.swt.layout.RowLayout;
73 import org.eclipse.swt.widgets.Button;
74 import org.eclipse.swt.widgets.ColorDialog;
75 import org.eclipse.swt.widgets.Composite;
76 import org.eclipse.swt.widgets.Control;
77 import org.eclipse.swt.widgets.Display;
78 import org.eclipse.swt.widgets.FileDialog;
79 import org.eclipse.swt.widgets.FontDialog;
80 import org.eclipse.swt.widgets.Label;
81 import org.eclipse.swt.widgets.Slider;
82 import org.eclipse.swt.widgets.Text;
83 
84 import java.awt.Paint;
85 import java.awt.image.BufferedImage;
86 import java.io.ByteArrayInputStream;
87 import java.io.ByteArrayOutputStream;
88 import java.io.File;
89 import java.io.IOException;
90 import java.io.InputStream;
91 import java.util.Collections;
92 import java.util.Iterator;
93 import java.util.LinkedHashMap;
94 import java.util.Map;
95 import java.util.Map.Entry;
96 
97 import javax.imageio.ImageIO;
98 
99 /**
100  * This is normally page 2 of a Create New Asset Set wizard, unless we can offer actions
101  * to create a specific asset type, in which case we skip page 1. On this page the user
102  * gets to configure the parameters of the asset, and see a preview.
103  */
104 public class ConfigureAssetSetPage extends WizardPage implements SelectionListener,
105         ModifyListener {
106     private final CreateAssetSetWizardState mValues;
107 
108     private static final int PREVIEW_AREA_WIDTH = 144;
109 
110     private boolean mShown;
111 
112     private Composite mConfigurationArea;
113     private Button mImageRadio;
114     private Button mClipartRadio;
115     private Button mTextRadio;
116     private Button mPickImageButton;
117     private Button mTrimCheckBox;
118     private Slider mPaddingSlider;
119     private Label mPercentLabel;
120     private Button mCropRadio;
121     private Button mCenterRadio;
122     private Button mNoShapeRadio;
123     private Button mSquareRadio;
124     private Button mCircleButton;
125     private Button mBgButton;
126     private Button mFgButton;
127     private Composite mPreviewArea;
128     private Button mFontButton;
129     private Composite mForegroundArea;
130     private Composite mImageForm;
131     private Composite mClipartForm;
132     private Composite mTextForm;
133     private Text mImagePathText;
134 
135     private boolean mTimerPending;
136     private RGB mBgColor;
137     private RGB mFgColor;
138     private Text mText;
139 
140     /** Most recently set image path: preserved across wizard sessions */
141     private static String sImagePath;
142     private Button mChooseClipart;
143     private Composite mClipartPreviewPanel;
144     private Label mThemeLabel;
145     private Composite mThemeComposite;
146     private Button mHoloLightRadio;
147     private Button mHoloDarkRadio;
148     private Label mScalingLabel;
149     private Composite mScalingComposite;
150     private Label mShapeLabel;
151     private Composite mShapeComposite;
152     private Label mBgColorLabel;
153     private Label mFgColorLabel;
154 
155     private boolean mIgnore;
156     private SourceType mShowingType;
157 
158     /**
159      * Create the wizard.
160      *
161      * @param values the wizard state
162      */
ConfigureAssetSetPage(CreateAssetSetWizardState values)163     public ConfigureAssetSetPage(CreateAssetSetWizardState values) {
164         super("configureAssetPage");
165         mValues = values;
166 
167         setTitle("Configure Icon Set");
168         setDescription("Configure the attributes of the icon set");
169     }
170 
171     /**
172      * Create contents of the wizard.
173      *
174      * @param parent the parent widget
175      */
176     @Override
177     @SuppressWarnings("unused") // Don't warn about unassigned "new Label(.)": has side-effect
createControl(Composite parent)178     public void createControl(Composite parent) {
179         Composite container = new Composite(parent, SWT.NULL);
180 
181         setControl(container);
182         GridLayout glContainer = new GridLayout(2, false);
183         glContainer.marginWidth = 0;
184         glContainer.horizontalSpacing = 0;
185         glContainer.marginHeight = 0;
186         glContainer.verticalSpacing = 0;
187         container.setLayout(glContainer);
188 
189         ScrolledComposite configurationScrollArea = new ScrolledComposite(container, SWT.V_SCROLL);
190         configurationScrollArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));
191         configurationScrollArea.setExpandHorizontal(true);
192         configurationScrollArea.setExpandVertical(true);
193 
194         mConfigurationArea = new Composite(configurationScrollArea, SWT.NONE);
195         GridLayout glConfigurationArea = new GridLayout(3, false);
196         glConfigurationArea.horizontalSpacing = 0;
197         glConfigurationArea.marginRight = 15;
198         glConfigurationArea.marginWidth = 0;
199         glConfigurationArea.marginHeight = 0;
200         mConfigurationArea.setLayout(glConfigurationArea);
201 
202         Label foregroundLabel = new Label(mConfigurationArea, SWT.NONE);
203         foregroundLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
204         foregroundLabel.setText("Foreground:");
205 
206         Composite foregroundComposite = new Composite(mConfigurationArea, SWT.NONE);
207         foregroundComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
208         GridLayout glForegroundComposite = new GridLayout(5, false);
209         glForegroundComposite.horizontalSpacing = 0;
210         foregroundComposite.setLayout(glForegroundComposite);
211 
212         mImageRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE);
213         mImageRadio.setSelection(false);
214         mImageRadio.addSelectionListener(this);
215         mImageRadio.setText("Image");
216 
217         mClipartRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE);
218         mClipartRadio.setText("Clipart");
219         mClipartRadio.addSelectionListener(this);
220 
221         mTextRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE);
222         mTextRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
223         mTextRadio.setText("Text");
224         mTextRadio.addSelectionListener(this);
225         new Label(mConfigurationArea, SWT.NONE);
226 
227         mForegroundArea = new Composite(mConfigurationArea, SWT.NONE);
228         mForegroundArea.setLayout(new StackLayout());
229         mForegroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
230 
231         mImageForm = new Composite(mForegroundArea, SWT.NONE);
232         mImageForm.setLayout(new GridLayout(3, false));
233 
234         Label fileLabel = new Label(mImageForm, SWT.NONE);
235         fileLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
236         fileLabel.setText("Image File:");
237 
238         mImagePathText = new Text(mImageForm, SWT.BORDER);
239         GridData pathLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
240         pathLayoutData.widthHint = 200;
241         mImagePathText.setLayoutData(pathLayoutData);
242         mImagePathText.addSelectionListener(this);
243         mImagePathText.addModifyListener(this);
244 
245         mPickImageButton = new Button(mImageForm, SWT.FLAT);
246         mPickImageButton.setText("Browse...");
247         mPickImageButton.addSelectionListener(this);
248 
249         mClipartForm = new Composite(mForegroundArea, SWT.NONE);
250         mClipartForm.setLayout(new GridLayout(2, false));
251 
252         mChooseClipart = new Button(mClipartForm, SWT.FLAT);
253         mChooseClipart.setText("Choose...");
254         mChooseClipart.addSelectionListener(this);
255 
256         mClipartPreviewPanel = new Composite(mClipartForm, SWT.NONE);
257         RowLayout rlClipartPreviewPanel = new RowLayout(SWT.HORIZONTAL);
258         rlClipartPreviewPanel.marginBottom = 0;
259         rlClipartPreviewPanel.marginTop = 0;
260         rlClipartPreviewPanel.center = true;
261         mClipartPreviewPanel.setLayout(rlClipartPreviewPanel);
262         mClipartPreviewPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
263 
264         mTextForm = new Composite(mForegroundArea, SWT.NONE);
265         mTextForm.setLayout(new GridLayout(2, false));
266 
267         Label textLabel = new Label(mTextForm, SWT.NONE);
268         textLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
269         textLabel.setText("Text:");
270 
271         mText = new Text(mTextForm, SWT.BORDER);
272         mText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
273         mText.addModifyListener(this);
274 
275         Label fontLabel = new Label(mTextForm, SWT.NONE);
276         fontLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
277         fontLabel.setText("Font:");
278 
279         mFontButton = new Button(mTextForm, SWT.FLAT);
280         mFontButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
281         mFontButton.addSelectionListener(this);
282         mFontButton.setText("Choose Font...");
283         new Label(mConfigurationArea, SWT.NONE);
284 
285         mTrimCheckBox = new Button(mConfigurationArea, SWT.CHECK);
286         mTrimCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
287         mTrimCheckBox.setSelection(false);
288         mTrimCheckBox.setText("Trim Surrounding Blank Space");
289         mTrimCheckBox.addSelectionListener(this);
290         new Label(mConfigurationArea, SWT.NONE);
291 
292         Label paddingLabel = new Label(mConfigurationArea, SWT.NONE);
293         paddingLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
294         paddingLabel.setText("Additional Padding:");
295         new Label(mConfigurationArea, SWT.NONE);
296 
297         mPaddingSlider = new Slider(mConfigurationArea, SWT.NONE);
298         mPaddingSlider.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
299         // This doesn't work right -- not sure why. For now just use a plain slider
300         // and subtract 10 from it to get the real range.
301         //mPaddingSlider.setValues(0, -10, 50, 0, 1, 10);
302         //mPaddingSlider.setSelection(10 + 15);
303         mPaddingSlider.addSelectionListener(this);
304 
305         mPercentLabel = new Label(mConfigurationArea, SWT.NONE);
306         mPercentLabel.setText("  15%"); // Enough available space for -10%
307         mScalingLabel = new Label(mConfigurationArea, SWT.NONE);
308         mScalingLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
309         mScalingLabel.setText("Foreground Scaling:");
310 
311         mScalingComposite = new Composite(mConfigurationArea, SWT.NONE);
312         mScalingComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
313         GridLayout gl_mScalingComposite = new GridLayout(5, false);
314         gl_mScalingComposite.horizontalSpacing = 0;
315         mScalingComposite.setLayout(gl_mScalingComposite);
316 
317         mCropRadio = new Button(mScalingComposite, SWT.FLAT | SWT.TOGGLE);
318         mCropRadio.setSelection(true);
319         mCropRadio.setText("Crop");
320         mCropRadio.addSelectionListener(this);
321 
322         mCenterRadio = new Button(mScalingComposite, SWT.FLAT | SWT.TOGGLE);
323         mCenterRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1));
324         mCenterRadio.setText("Center");
325         mCenterRadio.addSelectionListener(this);
326 
327         mShapeLabel = new Label(mConfigurationArea, SWT.NONE);
328         mShapeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
329         mShapeLabel.setText("Shape");
330 
331         mShapeComposite = new Composite(mConfigurationArea, SWT.NONE);
332         mShapeComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
333         GridLayout gl_mShapeComposite = new GridLayout(6, false);
334         gl_mShapeComposite.horizontalSpacing = 0;
335         mShapeComposite.setLayout(gl_mShapeComposite);
336 
337         mNoShapeRadio = new Button(mShapeComposite, SWT.FLAT | SWT.TOGGLE);
338         mNoShapeRadio.setText("None");
339         mNoShapeRadio.addSelectionListener(this);
340 
341         mSquareRadio = new Button(mShapeComposite, SWT.FLAT | SWT.TOGGLE);
342         mSquareRadio.setSelection(true);
343         mSquareRadio.setText("Square");
344         mSquareRadio.addSelectionListener(this);
345 
346         mCircleButton = new Button(mShapeComposite, SWT.FLAT | SWT.TOGGLE);
347         mCircleButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1));
348         mCircleButton.setText("Circle");
349         mCircleButton.addSelectionListener(this);
350 
351         mThemeLabel = new Label(mConfigurationArea, SWT.NONE);
352         mThemeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
353         mThemeLabel.setText("Theme");
354 
355         mThemeComposite = new Composite(mConfigurationArea, SWT.NONE);
356         mThemeComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
357         GridLayout gl_mThemeComposite = new GridLayout(2, false);
358         gl_mThemeComposite.horizontalSpacing = 0;
359         mThemeComposite.setLayout(gl_mThemeComposite);
360 
361         mHoloLightRadio = new Button(mThemeComposite, SWT.FLAT | SWT.TOGGLE);
362         mHoloLightRadio.setText("Holo Light");
363         mHoloLightRadio.setSelection(true);
364         mHoloLightRadio.addSelectionListener(this);
365 
366         mHoloDarkRadio = new Button(mThemeComposite, SWT.FLAT | SWT.TOGGLE);
367         mHoloDarkRadio.setText("Holo Dark");
368         mHoloDarkRadio.addSelectionListener(this);
369 
370         mBgColorLabel = new Label(mConfigurationArea, SWT.NONE);
371         mBgColorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
372         mBgColorLabel.setText("Background Color:");
373 
374         mBgButton = new Button(mConfigurationArea, SWT.FLAT);
375         mBgButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
376         mBgButton.addSelectionListener(this);
377         mBgButton.setAlignment(SWT.CENTER);
378 
379         mFgColorLabel = new Label(mConfigurationArea, SWT.NONE);
380         mFgColorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
381         mFgColorLabel.setText("Foreground Color:");
382 
383         mFgButton = new Button(mConfigurationArea, SWT.FLAT);
384         mFgButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
385         mFgButton.setAlignment(SWT.CENTER);
386         mFgButton.addSelectionListener(this);
387 
388         configurationScrollArea.setContent(mConfigurationArea);
389         configurationScrollArea.setMinSize(mConfigurationArea.computeSize(SWT.DEFAULT,
390                 SWT.DEFAULT));
391 
392         Label previewLabel = new Label(container, SWT.NONE);
393         previewLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
394         previewLabel.setText("Preview:");
395 
396         mPreviewArea = new Composite(container, SWT.BORDER);
397 
398         RowLayout rlPreviewAreaPreviewArea = new RowLayout(SWT.HORIZONTAL);
399         rlPreviewAreaPreviewArea.wrap = true;
400         rlPreviewAreaPreviewArea.pack = true;
401         rlPreviewAreaPreviewArea.center = true;
402         rlPreviewAreaPreviewArea.spacing = 0;
403         rlPreviewAreaPreviewArea.marginBottom = 0;
404         rlPreviewAreaPreviewArea.marginTop = 0;
405         rlPreviewAreaPreviewArea.marginRight = 0;
406         rlPreviewAreaPreviewArea.marginLeft = 0;
407         mPreviewArea.setLayout(rlPreviewAreaPreviewArea);
408         GridData gdMPreviewArea = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
409         gdMPreviewArea.widthHint = PREVIEW_AREA_WIDTH;
410         mPreviewArea.setLayoutData(gdMPreviewArea);
411 
412         // Initial color
413         Display display = parent.getDisplay();
414         updateColor(display, mValues.background, true /*background*/);
415         updateColor(display, mValues.foreground, false /*background*/);
416 
417         setSourceType(mValues.sourceType);
418 
419         new Label(mConfigurationArea, SWT.NONE);
420         new Label(mConfigurationArea, SWT.NONE);
421         new Label(mConfigurationArea, SWT.NONE);
422 
423         validatePage();
424     }
425 
configureAssetType(AssetType type)426     void configureAssetType(AssetType type) {
427         if (mValues.sourceType != mShowingType) {
428             mShowingType = mValues.sourceType;
429             showGroup(type.needsForegroundScaling(), mScalingLabel, mScalingComposite);
430             showGroup(type.needsShape(), mShapeLabel, mShapeComposite);
431             showGroup(type.needsTheme(), mThemeLabel, mThemeComposite);
432             showGroup(type.needsColors(), mBgColorLabel, mBgButton);
433             showGroup(type.needsColors() && mValues.sourceType != SourceType.IMAGE,
434                     mFgColorLabel, mFgButton);
435 
436             Composite parent = mScalingLabel.getParent();
437             parent.pack();
438             parent.layout();
439         }
440     }
441 
showGroup(boolean show, Control control1, Control control2)442     private static void showGroup(boolean show, Control control1, Control control2) {
443         showControl(show, control1);
444         showControl(show, control2);
445     }
446 
showControl(boolean show, Control control)447     private static void showControl(boolean show, Control control) {
448         Object data = control.getLayoutData();
449         if (data instanceof GridData) {
450             GridData gridData = (GridData) data;
451             gridData.exclude = !show;
452         }
453         control.setVisible(show);
454     }
455 
456     @Override
setVisible(boolean visible)457     public void setVisible(boolean visible) {
458         super.setVisible(visible);
459 
460         // We update the image selection here rather than in {@link #createControl} because
461         // that method is called when the wizard is created, and we want to wait until the
462         // user has chosen a project before attempting to look up the right default image to use
463         if (visible) {
464             mShown = true;
465 
466             // Clear out old previews - important if the user goes back to page one, changes
467             // asset type and steps into page 2 - at that point we arrive here and we might
468             // display the old previews for a brief period until the preview delay timer expires.
469             for (Control c : mPreviewArea.getChildren()) {
470                 c.dispose();
471             }
472             mPreviewArea.layout(true);
473 
474             // Update asset type configuration: will show/hide parameter controls depending
475             // on which asset type is chosen
476             AssetType type = mValues.type;
477             assert type != null;
478             configureAssetType(type);
479 
480             // Initial image - use the most recently used image, or the default launcher
481             // icon created in our default projects, if there
482             if (mValues.imagePath != null) {
483                 sImagePath = mValues.imagePath.getPath();
484             }
485             if (sImagePath == null) {
486                 IProject project = mValues.project;
487                 if (project != null) {
488                     IResource icon = project.findMember("res/drawable-hdpi/icon.png"); //$NON-NLS-1$
489                     if (icon != null) {
490                         IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot();
491                         IPath workspacePath = workspace.getLocation();
492                         sImagePath = workspacePath.append(icon.getFullPath()).toOSString();
493                     }
494                 }
495             }
496             if (sImagePath != null) {
497                 mValues.imagePath = new File(sImagePath);
498                 mImagePathText.setText(sImagePath);
499             }
500 
501             try {
502                 mIgnore = true;
503 
504                 mTrimCheckBox.setSelection(mValues.trim);
505 
506                 // This doesn't work right -- not sure why. For now just use a plain slider
507                 // and subtract 10 from it to get the real range.
508                 //mPaddingSlider.setValues(0, -10, 50, 0, 1, 10);
509                 //mPaddingSlider.setSelection(10 + 15);
510                 mPaddingSlider.setSelection(mValues.padding + 10);
511                 mPercentLabel.setText(Integer.toString(mValues.padding) + '%');
512 
513                 if (mValues.imagePath != null) {
514                     mImagePathText.setText(mValues.imagePath.getPath());
515                 }
516 
517                 if (mValues.text != null) {
518                     mText.setText(mValues.text);
519                 }
520 
521                 setSourceType(mValues.sourceType);
522 
523                 // Shape=NONE does not apply for notification icons; it's needed for API < 9
524                 if (mValues.shape == Shape.NONE && mValues.type == AssetType.NOTIFICATION) {
525                     mValues.shape = Shape.SQUARE;
526                 }
527 
528                 setShape(mValues.shape);
529                 mNoShapeRadio.setEnabled(mValues.type != AssetType.NOTIFICATION);
530 
531                 if (mValues.sourceType == SourceType.CLIPART
532                         && mValues.clipartName != null) {
533                     updateClipartPreview();
534                 }
535 
536                 // Initial color
537                 Display display = mPreviewArea.getDisplay();
538                 //updateColor(display, new RGB(0xa4, 0xc6, 0x39), true /*background*/);
539                 updateColor(display, mValues.background, true /*background*/);
540                 updateColor(display, mValues.foreground, false /*background*/);
541 
542                 updateTrimOptions();
543             } finally {
544                 mIgnore = false;
545             }
546 
547             validatePage();
548 
549             requestUpdatePreview(true /*quickly*/);
550 
551             if (mTextRadio.getSelection()) {
552                 mText.setFocus();
553             }
554         }
555     }
556 
setSourceType(CreateAssetSetWizardState.SourceType sourceType)557     private void setSourceType(CreateAssetSetWizardState.SourceType sourceType) {
558         if (sourceType == CreateAssetSetWizardState.SourceType.IMAGE) {
559             chooseForegroundTab(mImageRadio, mImageForm);
560         } else if (sourceType == CreateAssetSetWizardState.SourceType.CLIPART) {
561             chooseForegroundTab(mClipartRadio, mClipartForm);
562             mChooseClipart.setFocus();
563         } else if (sourceType == CreateAssetSetWizardState.SourceType.TEXT) {
564             updateFontLabel();
565             chooseForegroundTab(mTextRadio, mTextForm);
566             mText.setFocus();
567         }
568     }
569 
updateTrimOptions()570     private void updateTrimOptions() {
571         // Trimming and padding is not available for clipart images; padding etc is
572         // predefined to work well with action bar icons
573         if (mValues.sourceType == SourceType.CLIPART
574                 && mValues.type == AssetType.ACTIONBAR) {
575             mTrimCheckBox.setEnabled(false);
576             mPaddingSlider.setEnabled(false);
577             mValues.trim = false;
578         } else if (!mTrimCheckBox.isEnabled()) {
579             mTrimCheckBox.setEnabled(true);
580             mPaddingSlider.setEnabled(true);
581         }
582     }
583 
validatePage()584     private boolean validatePage() {
585         String error = null;
586         //String warning = null;
587 
588         if (mImageRadio.getSelection()) {
589             String path = mValues.imagePath != null ? mValues.imagePath.getPath() : null;
590             if (path == null || path.length() == 0) {
591                 error = "Select an image";
592             } else if (path.equals(DEFAULT_LAUNCHER_ICON)) {
593                 // Silent
594             } else if (!(new File(path).exists())) {
595                 error = String.format("%1$s does not exist", path);
596             } else {
597                 // Preserve across wizard sessions
598                 sImagePath = path;
599             }
600         } else if (mTextRadio.getSelection()) {
601             if (mValues.text.length() == 0) {
602                 error = "Enter text";
603             }
604         } else {
605             assert mClipartRadio.getSelection();
606             if (mValues.clipartName == null) {
607                 error = "Select clip art";
608             }
609         }
610 
611         setPageComplete(error == null);
612         if (error != null) {
613             setMessage(error, IMessageProvider.ERROR);
614         //} else if (warning != null) {
615         //    setMessage(warning, IMessageProvider.WARNING);
616         } else {
617             setErrorMessage(null);
618             setMessage(null);
619         }
620 
621         return error == null;
622     }
623 
624     @Override
isPageComplete()625     public boolean isPageComplete() {
626         // Force user to reach second page before hitting Finish
627         return mShown;
628     }
629 
630     // ---- Implements ModifyListener ----
631 
632     @Override
modifyText(ModifyEvent e)633     public void modifyText(ModifyEvent e) {
634         if (mIgnore) {
635             return;
636         }
637 
638         if (e.getSource() == mImagePathText) {
639             mValues.imagePath = new File(mImagePathText.getText().trim());
640             requestUpdatePreview(false);
641         } else if (e.getSource() == mText) {
642             mValues.text = mText.getText().trim();
643             requestUpdatePreview(false);
644         }
645 
646         validatePage();
647     }
648 
649     // ---- Implements SelectionListener ----
650 
651     @Override
widgetDefaultSelected(SelectionEvent e)652     public void widgetDefaultSelected(SelectionEvent e) {
653         // Nothing to do
654     }
655 
656     @Override
widgetSelected(SelectionEvent e)657     public void widgetSelected(SelectionEvent e) {
658         if (mIgnore) {
659             return;
660         }
661 
662         Object source = e.getSource();
663         boolean updateQuickly = true;
664 
665         // Tabs
666         if (source == mImageRadio) {
667             mValues.sourceType = CreateAssetSetWizardState.SourceType.IMAGE;
668             chooseForegroundTab((Button) source, mImageForm);
669             configureAssetType(mValues.type);
670             updateTrimOptions();
671         } else if (source == mClipartRadio) {
672             mValues.sourceType = CreateAssetSetWizardState.SourceType.CLIPART;
673             chooseForegroundTab((Button) source, mClipartForm);
674             configureAssetType(mValues.type);
675             updateTrimOptions();
676         } else if (source == mTextRadio) {
677             mValues.sourceType = CreateAssetSetWizardState.SourceType.TEXT;
678             updateFontLabel();
679             chooseForegroundTab((Button) source, mTextForm);
680             configureAssetType(mValues.type);
681             mText.setFocus();
682             updateTrimOptions();
683         }
684 
685         // Choose image file
686         if (source == mPickImageButton) {
687             FileDialog dialog = new FileDialog(mPickImageButton.getShell(), SWT.OPEN);
688 
689             String curLocation = mImagePathText.getText().trim();
690             if (!curLocation.isEmpty()) {
691                 dialog.setFilterPath(curLocation);
692             }
693 
694             String file = dialog.open();
695             if (file != null) {
696                 mValues.imagePath = new File(file);
697                 mImagePathText.setText(file);
698             }
699         }
700 
701         // Enforce Radio Groups
702         if (source == mCropRadio) {
703             mCropRadio.setSelection(true); // Ensure that you can't toggle it off
704             mCenterRadio.setSelection(false);
705             mValues.crop = true;
706         } else if (source == mCenterRadio) {
707             mCenterRadio.setSelection(true);
708             mCropRadio.setSelection(false);
709             mValues.crop = false;
710         }
711         if (source == mSquareRadio) {
712             mValues.shape = GraphicGenerator.Shape.SQUARE;
713             setShape(mValues.shape);
714         } else if (source == mCircleButton) {
715             mValues.shape = GraphicGenerator.Shape.CIRCLE;
716             setShape(mValues.shape);
717         } else if (source == mNoShapeRadio) {
718             mValues.shape = GraphicGenerator.Shape.NONE;
719             setShape(mValues.shape);
720         }
721 
722         if (source == mTrimCheckBox) {
723             mValues.trim = mTrimCheckBox.getSelection();
724         }
725 
726         if (source == mHoloDarkRadio) {
727             mHoloDarkRadio.setSelection(true);
728             mHoloLightRadio.setSelection(false);
729             mValues.holoDark = true;
730         } else if (source == mHoloLightRadio) {
731             mHoloLightRadio.setSelection(true);
732             mHoloDarkRadio.setSelection(false);
733             mValues.holoDark = false;
734         }
735 
736         if (source == mChooseClipart) {
737             MessageDialog dialog = new MessageDialog(mChooseClipart.getShell(),
738                     "Choose Clip Art",
739                     null, "Choose Clip Art Image:", MessageDialog.NONE,
740                     new String[] { "Close" }, 0) {
741                 @Override
742                 protected Control createCustomArea(Composite parent) {
743                     // Outer form which just establishes a width for the inner form which
744                     // wraps in a RowLayout
745                     Composite outer = new Composite(parent, SWT.NONE);
746                     GridLayout gridLayout = new GridLayout();
747                     outer.setLayout(gridLayout);
748 
749                     Composite chooserForm = new Composite(outer, SWT.NONE);
750                     GridData gd = new GridData();
751                     gd.grabExcessVerticalSpace = true;
752                     gd.widthHint = 450;
753                     chooserForm.setLayoutData(gd);
754                     RowLayout clipartFormLayout = new RowLayout(SWT.HORIZONTAL);
755                     clipartFormLayout.center = true;
756                     clipartFormLayout.wrap = true;
757                     chooserForm.setLayout(clipartFormLayout);
758 
759                     MouseAdapter clickListener = new MouseAdapter() {
760                         @Override
761                         public void mouseDown(MouseEvent event) {
762                             // Clicked on some of the sample art
763                             if (event.widget instanceof ImageControl) {
764                                 ImageControl image = (ImageControl) event.widget;
765                                 mValues.clipartName = (String) image.getData();
766                                 close();
767 
768                                 updateClipartPreview();
769                                 updatePreview();
770                             }
771                         }
772                     };
773                     Display display = chooserForm.getDisplay();
774                     Color hoverColor = display.getSystemColor(SWT.COLOR_RED);
775                     Iterator<String> clipartImages = GraphicGenerator.getClipartNames();
776                     while (clipartImages.hasNext()) {
777                         String name = clipartImages.next();
778                         try {
779                             BufferedImage icon = GraphicGenerator.getClipartIcon(name);
780                             if (icon != null) {
781                                 Image swtImage = SwtUtils.convertToSwt(display, icon, true, -1);
782                                 ImageControl img = new ImageControl(chooserForm,
783                                         SWT.NONE, swtImage);
784                                 img.setData(name);
785                                 img.setHoverColor(hoverColor);
786                                 img.addMouseListener(clickListener);
787                             }
788                         } catch (IOException e1) {
789                             AdtPlugin.log(e1, null);
790                         }
791                     }
792                     outer.pack();
793                     outer.layout();
794                     return outer;
795                 }
796             };
797             dialog.open();
798         }
799 
800         if (source == mBgButton) {
801             ColorDialog dlg = new ColorDialog(mBgButton.getShell());
802             dlg.setRGB(mBgColor);
803             dlg.setText("Choose a new Background Color");
804             RGB rgb = dlg.open();
805             if (rgb != null) {
806                 // Dispose the old color, create the
807                 // new one, and set into the label
808                 mValues.background = rgb;
809                 updateColor(mBgButton.getDisplay(), rgb, true /*background*/);
810             }
811         } else if (source == mFgButton) {
812             ColorDialog dlg = new ColorDialog(mFgButton.getShell());
813             dlg.setRGB(mFgColor);
814             dlg.setText("Choose a new Foreground Color");
815             RGB rgb = dlg.open();
816             if (rgb != null) {
817                 // Dispose the old color, create the
818                 // new one, and set into the label
819                 mValues.foreground = rgb;
820                 updateColor(mFgButton.getDisplay(), rgb, false /*background*/);
821             }
822         }
823 
824         if (source == mFontButton) {
825             FontDialog dialog = new FontDialog(mFontButton.getShell());
826             FontData[] fontList;
827             if (mFontButton.getData() == null) {
828                 fontList = mFontButton.getDisplay().getFontList(
829                         mValues.getTextFont().getFontName(), true /*scalable*/);
830             } else {
831                 fontList = mFontButton.getFont().getFontData();
832             }
833             dialog.setFontList(fontList);
834             FontData data = dialog.open();
835             if (data != null) {
836                 Font font = new Font(mFontButton.getDisplay(), dialog.getFontList());
837                 mFontButton.setFont(font);
838                 mFontButton.setData(font);
839 
840                 // Always use a large font for the rendering, even though user is typically
841                 // picking small font sizes in the font chooser
842                 //int dpi = mFontButton.getDisplay().getDPI().y;
843                 //int height = (int) Math.round(fontData.getHeight() * dpi / 72.0);
844                 int fontHeight = new TextRenderUtil.Options().fontSize;
845                 FontData fontData = font.getFontData()[0];
846                 int awtStyle = java.awt.Font.PLAIN;
847                 int swtStyle = fontData.getStyle();
848                 if ((swtStyle & SWT.ITALIC) != 0) {
849                     awtStyle |= java.awt.Font.ITALIC;
850                 }
851                 if ((swtStyle & SWT.BOLD) != 0) {
852                     awtStyle = java.awt.Font.BOLD;
853                 }
854                 mValues.setTextFont(new java.awt.Font(fontData.getName(), awtStyle, fontHeight));
855 
856                 updateFontLabel();
857                 mFontButton.getParent().pack();
858             }
859         }
860 
861         if (source == mPaddingSlider) {
862             mValues.padding = getPadding();
863             mPercentLabel.setText(Integer.toString(getPadding()) + '%');
864 
865             // When dragging the slider, only do periodic updates
866             updateQuickly = false;
867         }
868 
869         requestUpdatePreview(updateQuickly);
870     }
871 
872     @SuppressWarnings("unused") // SWT constructors have side effects and are not unused
updateClipartPreview()873     private void updateClipartPreview() {
874         for (Control c : mClipartPreviewPanel.getChildren()) {
875             c.dispose();
876         }
877         if (mClipartPreviewPanel.getChildren().length == 0) {
878             try {
879                 BufferedImage icon = GraphicGenerator.getClipartIcon(
880                         mValues.clipartName);
881                 if (icon != null) {
882                     Display display = mClipartForm.getDisplay();
883                     Image swtImage = SwtUtils.convertToSwt(display, icon,
884                             true, -1);
885                     new ImageControl(mClipartPreviewPanel,
886                             SWT.NONE, swtImage);
887                 }
888             } catch (IOException e1) {
889                 AdtPlugin.log(e1, null);
890             }
891             mClipartPreviewPanel.pack();
892             mClipartPreviewPanel.layout();
893         }
894     }
895 
setShape(GraphicGenerator.Shape shape)896     private void setShape(GraphicGenerator.Shape shape) {
897         if (shape == GraphicGenerator.Shape.SQUARE) {
898             mSquareRadio.setSelection(true);
899             mCircleButton.setSelection(false);
900             mNoShapeRadio.setSelection(false);
901         } else if (shape == GraphicGenerator.Shape.CIRCLE) {
902             mCircleButton.setSelection(true);
903             mSquareRadio.setSelection(false);
904             mNoShapeRadio.setSelection(false);
905         } else if (shape == GraphicGenerator.Shape.NONE) {
906             mNoShapeRadio.setSelection(true);
907             mCircleButton.setSelection(false);
908             mSquareRadio.setSelection(false);
909         } else {
910             assert false : shape;
911         }
912     }
913 
updateFontLabel()914     private void updateFontLabel() {
915         mFontButton.setText(mValues.getTextFont().getFontName());
916     }
917 
getPadding()918     private int getPadding() {
919         // Shifted - see comment for mPaddingSlider construction for an explanation
920         return mPaddingSlider.getSelection() - 10;
921     }
922 
chooseForegroundTab(Button newButton, Composite newArea)923     private void chooseForegroundTab(Button newButton, Composite newArea) {
924         if (newButton.getSelection()) {
925             mImageRadio.setSelection(false);
926             mClipartRadio.setSelection(false);
927             mTextRadio.setSelection(false);
928             newButton.setSelection(true);
929             StackLayout stackLayout = (StackLayout) mForegroundArea.getLayout();
930             stackLayout.topControl = newArea;
931             mForegroundArea.layout();
932         } else {
933             // Treat it as a radio button: you can't click to turn it off, you have to
934             // click on one of the other buttons
935             newButton.setSelection(true);
936         }
937     }
938 
939     /**
940      * Delay updates of the preview, to ensure that the SWT UI acts immediately (to handle
941      * radio group selections etc).
942      *
943      * @param quickly if true, update the previews soon, otherwise schedule one a bit later
944      */
requestUpdatePreview(boolean quickly)945     private void requestUpdatePreview(boolean quickly) {
946         if (mTimerPending) {
947             return;
948         }
949         mTimerPending = true;
950 
951         final Runnable timer = new Runnable() {
952             @Override
953             public void run() {
954                 mTimerPending = false;
955                 updatePreview();
956             }
957         };
958 
959         mPreviewArea.getDisplay().timerExec(quickly ? 10 : 250, timer);
960     }
961 
updatePreview()962     private void updatePreview() {
963         Display display = mPreviewArea.getDisplay();
964 
965         for (Control c : mPreviewArea.getChildren()) {
966             c.dispose();
967         }
968 
969         if (!validatePage()) {
970             return;
971         }
972 
973         Map<String, Map<String, BufferedImage>> map = generateImages(mValues,
974                 true /*previewOnly*/, this);
975         for (Entry<String, Map<String, BufferedImage>> categoryEntry : map.entrySet()) {
976             String category = categoryEntry.getKey();
977             if (category.length() > 0) {
978                 Label nameLabel = new Label(mPreviewArea, SWT.NONE);
979                 nameLabel.setText(String.format("%1$s:", category));
980                 RowData rowData = new RowData();
981                 nameLabel.setLayoutData(rowData);
982                 // Ensure these get their own rows
983                 rowData.width = PREVIEW_AREA_WIDTH;
984             }
985 
986             Map<String, BufferedImage> images = categoryEntry.getValue();
987             for (Entry<String, BufferedImage> entry :  images.entrySet()) {
988                 BufferedImage image = entry.getValue();
989                 Image swtImage = SwtUtils.convertToSwt(display, image, true, -1);
990                 if (swtImage != null) {
991                     @SuppressWarnings("unused") // Has side effect
992                     ImageControl imageControl = new ImageControl(mPreviewArea, SWT.NONE, swtImage);
993                 }
994             }
995         }
996 
997         mPreviewArea.layout(true);
998     }
999 
1000     /**
1001      * Generate images using the given wizard state
1002      *
1003      * @param mValues the state to use
1004      * @param previewOnly whether we are only generating previews
1005      * @param page if non null, a wizard page to write error messages to
1006      * @return a map of image objects
1007      */
generateImages( @onNull CreateAssetSetWizardState mValues, boolean previewOnly, @Nullable WizardPage page)1008     public static Map<String, Map<String, BufferedImage>> generateImages(
1009             @NonNull CreateAssetSetWizardState mValues,
1010             boolean previewOnly,
1011             @Nullable WizardPage page) {
1012         // Map of ids to images: Preserve insertion order (the densities)
1013         Map<String, Map<String, BufferedImage>> categoryMap =
1014                 new LinkedHashMap<String, Map<String, BufferedImage>>();
1015 
1016         AssetType type = mValues.type;
1017         boolean trim = mValues.trim;
1018 
1019         BufferedImage sourceImage = null;
1020         switch (mValues.sourceType) {
1021             case IMAGE: {
1022                 // Load the image
1023                 // TODO: Only do this when the source image type is image
1024                 String path = mValues.imagePath != null ? mValues.imagePath.getPath() : "";
1025                 if (path.length() == 0) {
1026                     if (page != null) {
1027                         page.setErrorMessage("Enter a filename");
1028                     }
1029                     return Collections.emptyMap();
1030                 }
1031                 if (!path.equals(DEFAULT_LAUNCHER_ICON)) {
1032                     File file = new File(path);
1033                     if (!file.isFile()) {
1034                         if (page != null) {
1035                             page.setErrorMessage(String.format("%1$s does not exist", file.getPath()));
1036                         }
1037                         return Collections.emptyMap();
1038                     }
1039                 }
1040 
1041                 if (page != null) {
1042                     page.setErrorMessage(null);
1043                 }
1044                 try {
1045                     sourceImage = mValues.getCachedImage(path, false);
1046                     if (sourceImage != null) {
1047                         if (trim) {
1048                             sourceImage = ImageUtils.cropBlank(sourceImage, null, TYPE_INT_ARGB);
1049                         }
1050                         if (mValues.padding != 0) {
1051                             sourceImage = Util.paddedImage(sourceImage, mValues.padding);
1052                         }
1053                     }
1054                 } catch (IOException ioe) {
1055                     if (page != null) {
1056                         page.setErrorMessage(ioe.getLocalizedMessage());
1057                     }
1058                 }
1059                 break;
1060             }
1061             case CLIPART: {
1062                 try {
1063                     sourceImage = GraphicGenerator.getClipartImage(mValues.clipartName);
1064 
1065                     boolean isActionBar = mValues.type == AssetType.ACTIONBAR;
1066                     if (trim && !isActionBar) {
1067                         sourceImage = ImageUtils.cropBlank(sourceImage, null, TYPE_INT_ARGB);
1068                     }
1069 
1070                     if (type.needsColors()) {
1071                         RGB fg = mValues.foreground;
1072                         int color = 0xFF000000 | (fg.red << 16) | (fg.green << 8) | fg.blue;
1073                         Paint paint = new java.awt.Color(color);
1074                         sourceImage = Util.filledImage(sourceImage, paint);
1075                     }
1076 
1077                     int padding = mValues.padding;
1078                     if (padding != 0 && !isActionBar) {
1079                         sourceImage = Util.paddedImage(sourceImage, padding);
1080                     }
1081                 } catch (IOException e) {
1082                     AdtPlugin.log(e, null);
1083                     return categoryMap;
1084                 }
1085                 break;
1086             }
1087             case TEXT: {
1088                 String text = mValues.text;
1089                 TextRenderUtil.Options options = new TextRenderUtil.Options();
1090                 options.font = mValues.getTextFont();
1091                 int color;
1092                 if (type.needsColors()) {
1093                     RGB fg = mValues.foreground;
1094                     color = 0xFF000000 | (fg.red << 16) | (fg.green << 8) | fg.blue;
1095                 } else {
1096                     color = 0xFFFFFFFF;
1097                 }
1098                 options.foregroundColor = color;
1099                 sourceImage = TextRenderUtil.renderTextImage(text, mValues.padding, options);
1100 
1101                 if (trim) {
1102                     sourceImage = ImageUtils.cropBlank(sourceImage, null, TYPE_INT_ARGB);
1103                 }
1104 
1105                 int padding = mValues.padding;
1106                 if (padding != 0) {
1107                     sourceImage = Util.paddedImage(sourceImage, padding);
1108                 }
1109                 break;
1110             }
1111         }
1112 
1113         GraphicGenerator generator = null;
1114         GraphicGenerator.Options options = null;
1115         switch (type) {
1116             case LAUNCHER: {
1117                 generator = new LauncherIconGenerator();
1118                 LauncherIconGenerator.LauncherOptions launcherOptions =
1119                         new LauncherIconGenerator.LauncherOptions();
1120                 launcherOptions.shape = mValues.shape;
1121                 launcherOptions.crop = mValues.crop;
1122                 launcherOptions.style = GraphicGenerator.Style.SIMPLE;
1123 
1124                 RGB bg = mValues.background;
1125                 int color = (bg.red << 16) | (bg.green << 8) | bg.blue;
1126                 launcherOptions.backgroundColor = color;
1127                 // Flag which tells the generator iterator to include a web graphic
1128                 launcherOptions.isWebGraphic = !previewOnly;
1129                 options = launcherOptions;
1130 
1131                 break;
1132             }
1133             case MENU:
1134                 generator = new MenuIconGenerator();
1135                 options = new GraphicGenerator.Options();
1136                 break;
1137             case ACTIONBAR: {
1138                 generator = new ActionBarIconGenerator();
1139                 ActionBarIconGenerator.ActionBarOptions actionBarOptions =
1140                         new ActionBarIconGenerator.ActionBarOptions();
1141                 actionBarOptions.theme = mValues.holoDark
1142                         ? ActionBarIconGenerator.Theme.HOLO_DARK
1143                                 : ActionBarIconGenerator.Theme.HOLO_LIGHT;
1144                 actionBarOptions.sourceIsClipart = (mValues.sourceType == SourceType.CLIPART);
1145 
1146                 options = actionBarOptions;
1147                 break;
1148             }
1149             case NOTIFICATION: {
1150                 generator = new NotificationIconGenerator();
1151                 options = new NotificationIconGenerator.NotificationOptions();
1152                 break;
1153             }
1154             case TAB:
1155                 generator = new TabIconGenerator();
1156                 options = new TabIconGenerator.TabOptions();
1157                 break;
1158             default:
1159                 AdtPlugin.log(IStatus.ERROR, "Unsupported asset type: %1$s", type);
1160                 return categoryMap;
1161         }
1162 
1163         options.sourceImage = sourceImage;
1164 
1165         IProject project = mValues.project;
1166         if (mValues.minSdk != -1) {
1167             options.minSdk = mValues.minSdk;
1168         } else {
1169             Pair<Integer, Integer> v = ManifestInfo.computeSdkVersions(project);
1170             options.minSdk = v.getFirst();
1171         }
1172 
1173         String baseName = mValues.outputName;
1174         generator.generate(null, categoryMap, mValues, options, baseName);
1175 
1176         return categoryMap;
1177     }
1178 
1179     /**
1180      * Generate custom icons into the project based on the asset studio wizard
1181      * state
1182      *
1183      * @param newProject the project to write into
1184      * @param values the wizard state to read configuration settings from
1185      * @param previewOnly whether we are only generating a preview. For example,
1186      *            the launcher icons won't generate a huge 512x512 web graphic
1187      *            in preview mode
1188      * @param page a wizard page to write error messages to, or null
1189      */
generateIcons(final IProject newProject, @NonNull CreateAssetSetWizardState values, boolean previewOnly, @Nullable WizardPage page)1190     public static void generateIcons(final IProject newProject,
1191             @NonNull CreateAssetSetWizardState values,
1192             boolean previewOnly,
1193             @Nullable WizardPage page) {
1194         // Generate the custom icons
1195         Map<String, Map<String, BufferedImage>> categories = generateImages(values,
1196                 false /*previewOnly*/, page);
1197         for (Map<String, BufferedImage> previews : categories.values()) {
1198             for (Map.Entry<String, BufferedImage> entry : previews.entrySet()) {
1199                 String relativePath = entry.getKey();
1200                 IPath dest = new Path(relativePath);
1201                 IFile file = newProject.getFile(dest);
1202 
1203                 // In case template already created icons (should remove that)
1204                 // remove them first
1205                 if (file.exists()) {
1206                     try {
1207                         file.delete(true, new NullProgressMonitor());
1208                     } catch (CoreException e) {
1209                         AdtPlugin.log(e, null);
1210                     }
1211                 }
1212                 AdtUtils.createWsParentDirectory(file.getParent());
1213                 BufferedImage image = entry.getValue();
1214 
1215                 ByteArrayOutputStream stream = new ByteArrayOutputStream();
1216                 try {
1217                     ImageIO.write(image, "PNG", stream); //$NON-NLS-1$
1218                     byte[] bytes = stream.toByteArray();
1219                     InputStream is = new ByteArrayInputStream(bytes);
1220                     file.create(is, true /*force*/, null /*progress*/);
1221                 } catch (IOException e) {
1222                     AdtPlugin.log(e, null);
1223                 } catch (CoreException e) {
1224                     AdtPlugin.log(e, null);
1225                 }
1226 
1227                 try {
1228                     file.getParent().refreshLocal(1, new NullProgressMonitor());
1229                 } catch (CoreException e) {
1230                     AdtPlugin.log(e, null);
1231                 }
1232             }
1233         }
1234     }
1235 
updateColor(Display display, RGB color, boolean isBackground)1236     private void updateColor(Display display, RGB color, boolean isBackground) {
1237         // Button.setBackgroundColor does not work (at least not on OSX) so
1238         // we instead have to use Button.setImage with an image of the given
1239         // color
1240         BufferedImage coloredImage = ImageUtils.createColoredImage(60, 20, color);
1241         Image image = SwtUtils.convertToSwt(display, coloredImage, false, -1);
1242 
1243         if (isBackground) {
1244             mBgColor = color;
1245             mBgButton.setImage(image);
1246         } else {
1247             mFgColor = color;
1248             mFgButton.setImage(image);
1249         }
1250     }
1251 }
1252