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
17package com.android.ide.eclipse.adt.internal.assetstudio;
18
19import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.DEFAULT_LAUNCHER_ICON;
20import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
21
22import com.android.annotations.NonNull;
23import com.android.annotations.Nullable;
24import com.android.assetstudiolib.ActionBarIconGenerator;
25import com.android.assetstudiolib.GraphicGenerator;
26import com.android.assetstudiolib.GraphicGenerator.Shape;
27import com.android.assetstudiolib.LauncherIconGenerator;
28import com.android.assetstudiolib.MenuIconGenerator;
29import com.android.assetstudiolib.NotificationIconGenerator;
30import com.android.assetstudiolib.TabIconGenerator;
31import com.android.assetstudiolib.TextRenderUtil;
32import com.android.assetstudiolib.Util;
33import com.android.ide.eclipse.adt.AdtPlugin;
34import com.android.ide.eclipse.adt.AdtUtils;
35import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState.SourceType;
36import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl;
37import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils;
38import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SwtUtils;
39import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
40import com.android.utils.Pair;
41
42import org.eclipse.core.resources.IFile;
43import org.eclipse.core.resources.IProject;
44import org.eclipse.core.resources.IResource;
45import org.eclipse.core.resources.IWorkspaceRoot;
46import org.eclipse.core.resources.ResourcesPlugin;
47import org.eclipse.core.runtime.CoreException;
48import org.eclipse.core.runtime.IPath;
49import org.eclipse.core.runtime.IStatus;
50import org.eclipse.core.runtime.NullProgressMonitor;
51import org.eclipse.core.runtime.Path;
52import org.eclipse.jface.dialogs.IMessageProvider;
53import org.eclipse.jface.dialogs.MessageDialog;
54import org.eclipse.jface.wizard.WizardPage;
55import org.eclipse.swt.SWT;
56import org.eclipse.swt.custom.ScrolledComposite;
57import org.eclipse.swt.custom.StackLayout;
58import org.eclipse.swt.events.ModifyEvent;
59import org.eclipse.swt.events.ModifyListener;
60import org.eclipse.swt.events.MouseAdapter;
61import org.eclipse.swt.events.MouseEvent;
62import org.eclipse.swt.events.SelectionEvent;
63import org.eclipse.swt.events.SelectionListener;
64import org.eclipse.swt.graphics.Color;
65import org.eclipse.swt.graphics.Font;
66import org.eclipse.swt.graphics.FontData;
67import org.eclipse.swt.graphics.Image;
68import org.eclipse.swt.graphics.RGB;
69import org.eclipse.swt.layout.GridData;
70import org.eclipse.swt.layout.GridLayout;
71import org.eclipse.swt.layout.RowData;
72import org.eclipse.swt.layout.RowLayout;
73import org.eclipse.swt.widgets.Button;
74import org.eclipse.swt.widgets.ColorDialog;
75import org.eclipse.swt.widgets.Composite;
76import org.eclipse.swt.widgets.Control;
77import org.eclipse.swt.widgets.Display;
78import org.eclipse.swt.widgets.FileDialog;
79import org.eclipse.swt.widgets.FontDialog;
80import org.eclipse.swt.widgets.Label;
81import org.eclipse.swt.widgets.Slider;
82import org.eclipse.swt.widgets.Text;
83
84import java.awt.Paint;
85import java.awt.image.BufferedImage;
86import java.io.ByteArrayInputStream;
87import java.io.ByteArrayOutputStream;
88import java.io.File;
89import java.io.IOException;
90import java.io.InputStream;
91import java.util.Collections;
92import java.util.Iterator;
93import java.util.LinkedHashMap;
94import java.util.Map;
95import java.util.Map.Entry;
96
97import 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 */
104public 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     */
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
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
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
442    private static void showGroup(boolean show, Control control1, Control control2) {
443        showControl(show, control1);
444        showControl(show, control2);
445    }
446
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
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
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
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
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
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
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
652    public void widgetDefaultSelected(SelectionEvent e) {
653        // Nothing to do
654    }
655
656    @Override
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
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
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
914    private void updateFontLabel() {
915        mFontButton.setText(mValues.getTextFont().getFontName());
916    }
917
918    private int getPadding() {
919        // Shifted - see comment for mPaddingSlider construction for an explanation
920        return mPaddingSlider.getSelection() - 10;
921    }
922
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     */
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
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     */
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     */
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
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