1/*******************************************************************************
2 * Copyright (c) 2011 Google, Inc.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Google, Inc. - initial API and implementation
10 *******************************************************************************/
11
12package org.eclipse.wb.internal.core;
13
14import com.google.common.collect.Maps;
15import com.google.common.io.CharStreams;
16import com.google.common.io.Closeables;
17
18import org.eclipse.core.runtime.IStatus;
19import org.eclipse.core.runtime.Status;
20import org.eclipse.jface.resource.ImageDescriptor;
21import org.eclipse.swt.graphics.Image;
22import org.eclipse.swt.widgets.Display;
23import org.eclipse.swt.widgets.Shell;
24import org.eclipse.ui.IWorkbenchWindow;
25import org.eclipse.ui.plugin.AbstractUIPlugin;
26
27import java.io.Closeable;
28import java.io.InputStream;
29import java.io.InputStreamReader;
30import java.net.URL;
31import java.nio.charset.Charset;
32import java.util.Map;
33
34/**
35 * The DesignerPlugin class is the "nexus" of the propertysheet. In WindowBuilder,
36 * it's the plugin activator, and contains a number of important utility methods, such
37 * as resource loading, logging, obtaining a display and shell, etc.
38 * <p>
39 * In the AOSP fork, most of the functionality has been ripped out, except for the
40 * above mentioned pieces, and this class is no longer a plugin. Instead, it *delegates*
41 * to the plugin which initializes it via the {@link #initialize} method for things
42 * like logging. For things like image loading, it has its own local code such that
43 * it can find its image resources locally instead of requiring the embedding plugin
44 * to copy the images into its own jar.
45 * <p>
46 * "DesignerPlugin" is not a very good name for this class since it is not a plugin,
47 * but it was left that way to avoid modifying all the various propertysheet classes;
48 * we'd like to keep those as unmodified as possible to make absorbing future
49 * WindowBuilder improvements as easy as possible.
50 */
51public class DesignerPlugin {
52    private static AbstractUIPlugin sPlugin;
53    private static String sPluginId;
54
55    /**
56     * Initialize the property sheet for use in the ADT plugin
57     *
58     * @param hostPlugin the plugin to embed the property sheet
59     * @param pluginId the id of the plugin to use in status messages etc
60     * @param isWindows whether we're running on Windows
61     * @param isMac whether we're running on Mac
62     * @param isLinux whether we're running on Linux
63     */
64    public static void initialize(AbstractUIPlugin hostPlugin, String pluginId,
65            boolean isWindows, boolean isMac, boolean isLinux) {
66        assert sPlugin == null; // Can only be used by one client in the same classloader
67        sPlugin = hostPlugin;
68        sPluginId = pluginId;
69        EnvironmentUtils.IS_WINDOWS = isWindows;
70        EnvironmentUtils.IS_MAC = isMac;
71        EnvironmentUtils.IS_LINUX = isLinux;
72    }
73
74    /**
75     * Dispose the propertysheet library: free up images from the cache, unregister the
76     * plugin reference etc.
77     */
78    public static void dispose() {
79        sPlugin = null;
80        for (Image image : sImageCache.values()) {
81            image.dispose();
82        }
83        sImageCache.clear();
84        sDescriptorCache.clear();
85    }
86
87    /**
88     * Reads the contents of an {@link InputStreamReader} using the default
89     * platform encoding and return it as a String. This method will close the
90     * input stream.
91     *
92     * @param inputStream the input stream to be read from
93     * @param charset the charset to use
94     * @return the String read from the stream, or null if there was an error
95     */
96    public static String readFile(InputStream inputStream, Charset charset) {
97        if (inputStream == null) {
98            return null;
99        }
100        Closeable closeMe = inputStream;
101        try {
102            final InputStreamReader isr = new InputStreamReader(inputStream, charset);
103            closeMe = isr;
104            try {
105                return CharStreams.toString(isr);
106            } catch (Exception ioe) {
107                // pass -- ignore files we can't read
108                return null;
109            }
110        } finally {
111            Closeables.closeQuietly(closeMe);
112        }
113    }
114
115    /**
116     * @return the instance of {@link DesignerPlugin}
117     */
118    public static AbstractUIPlugin getDefault() {
119        assert sPlugin != null;
120        return sPlugin;
121    }
122
123    // //////////////////////////////////////////////////////////////////////////
124    //
125    // Display/Shell
126    //
127    // //////////////////////////////////////////////////////////////////////////
128    /**
129     * @return the {@link Display} instance, current (if in GUI thread) or
130     *         default.
131     */
132    public static Display getStandardDisplay() {
133        Display display = Display.getCurrent();
134        if (display == null) {
135            display = Display.getDefault();
136        }
137        return display;
138    }
139
140    /**
141     * @return the active {@link IWorkbenchWindow}.
142     */
143    public static IWorkbenchWindow getActiveWorkbenchWindow() {
144        return getDefault().getWorkbench().getActiveWorkbenchWindow();
145    }
146
147    /**
148     * @return the {@link Shell} of active {@link IWorkbenchWindow}.
149     */
150    public static Shell getShell() {
151        if (getActiveWorkbenchWindow() != null) {
152            return getActiveWorkbenchWindow().getShell();
153        }
154        return null;
155    }
156
157    /**
158     * Logs given {@link IStatus} into Eclipse .log.
159     */
160    public static void log(IStatus status) {
161        getDefault().getLog().log(status);
162    }
163
164    /**
165     * Logs {@link IStatus} with given message into Eclipse .log.
166     */
167    public static void log(String message) {
168        log(new Status(IStatus.INFO, sPluginId, IStatus.INFO, message, null));
169    }
170
171    /**
172     * Logs {@link IStatus} with given exception into Eclipse .log.
173     */
174    public static void log(Throwable e) {
175        Status status = new Status(IStatus.ERROR, sPluginId, "", e);
176        getDefault().getLog().log(status);
177    }
178
179    /**
180     * Logs {@link IStatus} with given message and exception into Eclipse .log.
181     */
182    public static void log(String message, Throwable e) {
183        log(createStatus(message, e));
184    }
185
186    /**
187     * Creates {@link IStatus} for given message and exception.
188     */
189    public static Status createStatus(String message, Throwable e) {
190        return new Status(IStatus.ERROR, "wb", IStatus.ERROR, message, e) {
191            @Override
192            public boolean isMultiStatus() {
193                return true;
194            }
195        };
196    }
197
198    // //////////////////////////////////////////////////////////////////////////
199    //
200    // Resources
201    //
202    // //////////////////////////////////////////////////////////////////////////
203    private static Map<String, ImageDescriptor> sDescriptorCache = Maps.newHashMap();
204    private static Map<String, Image> sImageCache = Maps.newHashMap();
205
206    public static Image getImage(String path) {
207        Image image = sImageCache.get(path);
208        if (image == null) {
209            ImageDescriptor descriptor = getImageDescriptor(path);
210            if (descriptor != null) {
211                image = descriptor.createImage();
212            }
213            sImageCache.put(path, image);
214        }
215        return image;
216    }
217
218    public static ImageDescriptor getImageDescriptor(String path) {
219        ImageDescriptor descriptor = sDescriptorCache.get(path);
220        if (descriptor == null) {
221            URL url = DesignerPlugin.class.getResource("icons/" + path); //$NON-NLS-1$
222            if (url != null) {
223                descriptor = ImageDescriptor.createFromURL(url);
224                sDescriptorCache.put(path, descriptor);
225            }
226        }
227        return descriptor;
228    }
229}
230