1/*
2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.apple.laf;
27
28import java.awt.*;
29import java.awt.image.BufferedImage;
30import java.io.File;
31
32import javax.swing.*;
33import javax.swing.plaf.*;
34
35import apple.laf.JRSUIConstants.Size;
36import apple.laf.*;
37
38import com.apple.laf.AquaUtilControlSize.*;
39import com.apple.laf.AquaUtils.RecyclableSingleton;
40import sun.lwawt.macosx.CImage;
41
42public class AquaIcon {
43    interface InvertableIcon extends Icon {
44        public Icon getInvertedIcon();
45    }
46
47    static UIResource getIconFor(final JRSUIControlSpec spec, final int width, final int height) {
48        return new ScalingJRSUIIcon(width, height) {
49            @Override
50            public void initIconPainter(final AquaPainter<JRSUIState> painter) {
51                spec.initIconPainter(painter);
52            }
53        };
54    }
55
56    // converts an object that is an icon into an image so we can hand it off to AppKit
57    public static Image getImageForIcon(final Icon i) {
58        if (i instanceof ImageIcon) return ((ImageIcon)i).getImage();
59
60        final int w = i.getIconWidth();
61        final int h = i.getIconHeight();
62
63        if (w <= 0 || h <= 0) return null;
64
65        // This could be any kind of icon, so we need to make a buffer for it, draw it and then pass the new image off to appkit.
66        final BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
67        final Graphics g = image.getGraphics();
68        i.paintIcon(null, g, 0, 0);
69        g.dispose();
70        return image;
71    }
72
73    public interface JRSUIControlSpec {
74        public void initIconPainter(final AquaPainter<? extends JRSUIState> painter);
75    }
76
77    abstract static class JRSUIIcon implements Icon, UIResource {
78        protected final AquaPainter<JRSUIState> painter = AquaPainter.create(JRSUIState.getInstance());
79
80        public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
81            painter.paint(g, c, x, y, getIconWidth(), getIconHeight());
82        }
83    }
84
85    abstract static class DynamicallySizingJRSUIIcon extends JRSUIIcon {
86        protected final SizeDescriptor sizeDescriptor;
87        protected SizeVariant sizeVariant;
88
89        public DynamicallySizingJRSUIIcon(final SizeDescriptor sizeDescriptor) {
90            this.sizeDescriptor = sizeDescriptor;
91            this.sizeVariant = sizeDescriptor.regular;
92            initJRSUIState();
93        }
94
95        public abstract void initJRSUIState();
96
97        public int getIconHeight() {
98            return sizeVariant == null ? 0 : sizeVariant.h;
99        }
100
101        public int getIconWidth() {
102            return sizeVariant == null ? 0 : sizeVariant.w;
103        }
104
105        public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
106            final Size size = c instanceof JComponent ? AquaUtilControlSize.getUserSizeFrom((JComponent)c) : Size.REGULAR;
107            sizeVariant = sizeDescriptor.get(size);
108            painter.state.set(size);
109            super.paintIcon(c, g, x, y);
110        }
111    }
112
113    abstract static class CachingScalingIcon implements Icon, UIResource {
114        int width;
115        int height;
116        Image image;
117
118        public CachingScalingIcon(final int width, final int height) {
119            this.width = width;
120            this.height = height;
121        }
122
123        void setSize(final int width, final int height) {
124            this.width = width;
125            this.height = height;
126            this.image = null;
127        }
128
129        Image getImage() {
130            if (image != null) return image;
131
132            if (!GraphicsEnvironment.isHeadless()) {
133                image = createImage();
134            }
135
136            return image;
137        }
138
139        abstract Image createImage();
140
141        public boolean hasIconRef() {
142            return getImage() != null;
143        }
144
145        public void paintIcon(final Component c, Graphics g, final int x, final int y) {
146            g = g.create();
147
148            if (g instanceof Graphics2D) {
149                // improves icon rendering quality in Quartz
150                ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
151            }
152
153            final Image myImage = getImage();
154            if (myImage != null) {
155                g.drawImage(myImage, x, y, getIconWidth(), getIconHeight(), null);
156            }
157
158            g.dispose();
159        }
160
161        public int getIconWidth() {
162            return width;
163        }
164
165        public int getIconHeight() {
166            return height;
167        }
168
169    }
170
171    abstract static class ScalingJRSUIIcon implements Icon, UIResource {
172        final int width;
173        final int height;
174
175        public ScalingJRSUIIcon(final int width, final int height) {
176            this.width = width;
177            this.height = height;
178        }
179
180        @Override
181        public void paintIcon(final Component c, Graphics g,
182                final int x, final int y) {
183            if (GraphicsEnvironment.isHeadless()) {
184                return;
185            }
186
187            g = g.create();
188
189            if (g instanceof Graphics2D) {
190                // improves icon rendering quality in Quartz
191                ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING,
192                        RenderingHints.VALUE_RENDER_QUALITY);
193            }
194
195            final AquaPainter<JRSUIState> painter =
196                    AquaPainter.create(JRSUIState.getInstance());
197            initIconPainter(painter);
198
199            g.clipRect(x, y, width, height);
200            painter.paint(g, c, x, y, width, height);
201            g.dispose();
202        }
203
204        public abstract void initIconPainter(final AquaPainter<JRSUIState> painter);
205
206        @Override
207        public int getIconWidth() {
208            return width;
209        }
210
211        @Override
212        public int getIconHeight() {
213            return height;
214        }
215    }
216
217    static class FileIcon extends CachingScalingIcon {
218        final File file;
219
220        public FileIcon(final File file, final int width, final int height) {
221            super(width, height);
222            this.file = file;
223        }
224
225        public FileIcon(final File file) {
226            this(file, 16, 16);
227        }
228
229        Image createImage() {
230            return CImage.createImageOfFile(file.getAbsolutePath(), getIconWidth(), getIconHeight());
231        }
232    }
233
234    static class SystemIconSingleton extends RecyclableSingleton<SystemIcon> {
235        final String selector;
236
237        public SystemIconSingleton(String selector) {
238            this.selector = selector;
239        }
240
241        @Override
242        protected SystemIcon getInstance() {
243            return new SystemIcon(selector);
244        }
245    }
246
247    static class SystemIconUIResourceSingleton extends RecyclableSingleton<IconUIResource> {
248        final String selector;
249
250        public SystemIconUIResourceSingleton(String selector) {
251            this.selector = selector;
252        }
253
254        @Override
255        protected IconUIResource getInstance() {
256            return new IconUIResource(new SystemIcon(selector));
257        }
258    }
259
260    static class SystemIcon extends CachingScalingIcon {
261        private static final SystemIconUIResourceSingleton folderIcon = new SystemIconUIResourceSingleton("fldr");
262        static IconUIResource getFolderIconUIResource() { return folderIcon.get(); }
263
264        private static final SystemIconUIResourceSingleton openFolderIcon = new SystemIconUIResourceSingleton("ofld");
265        static IconUIResource getOpenFolderIconUIResource() { return openFolderIcon.get(); }
266
267        private static final SystemIconUIResourceSingleton desktopIcon = new SystemIconUIResourceSingleton("desk");
268        static IconUIResource getDesktopIconUIResource() { return desktopIcon.get(); }
269
270        private static final SystemIconUIResourceSingleton computerIcon = new SystemIconUIResourceSingleton("FNDR");
271        static IconUIResource getComputerIconUIResource() { return computerIcon.get(); }
272
273        private static final SystemIconUIResourceSingleton documentIcon = new SystemIconUIResourceSingleton("docu");
274        static IconUIResource getDocumentIconUIResource() { return documentIcon.get(); }
275
276        private static final SystemIconUIResourceSingleton hardDriveIcon = new SystemIconUIResourceSingleton("hdsk");
277        static IconUIResource getHardDriveIconUIResource() { return hardDriveIcon.get(); }
278
279        private static final SystemIconUIResourceSingleton floppyIcon = new SystemIconUIResourceSingleton("flpy");
280        static IconUIResource getFloppyIconUIResource() { return floppyIcon.get(); }
281
282        //private static final SystemIconUIResourceSingleton noteIcon = new SystemIconUIResourceSingleton("note");
283        //static IconUIResource getNoteIconUIResource() { return noteIcon.get(); }
284
285        private static final SystemIconSingleton caut = new SystemIconSingleton("caut");
286        static SystemIcon getCautionIcon() { return caut.get(); }
287
288        private static final SystemIconSingleton stop = new SystemIconSingleton("stop");
289        static SystemIcon getStopIcon() { return stop.get(); }
290
291        final String selector;
292
293        public SystemIcon(final String iconSelector, final int width, final int height) {
294            super(width, height);
295            selector = iconSelector;
296        }
297
298        public SystemIcon(final String iconSelector) {
299            this(iconSelector, 16, 16);
300        }
301
302        Image createImage() {
303            return CImage.createSystemImageFromSelector(
304                    selector, getIconWidth(), getIconHeight());
305        }
306    }
307}
308