View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.eclipse.common.util;
17  
18  import java.io.InputStream;
19  import java.lang.reflect.Field;
20  import java.lang.reflect.Modifier;
21  import java.net.URL;
22  import java.util.Enumeration;
23  import java.util.Locale;
24  import java.util.ResourceBundle;
25  
26  import org.eclipse.jface.resource.ImageDescriptor;
27  import org.eclipse.jface.resource.ImageRegistry;
28  import org.eclipse.swt.graphics.Image;
29  import org.eclipse.swt.graphics.ImageData;
30  import org.eclipse.swt.widgets.Display;
31  import org.seasar.framework.beans.BeanDesc;
32  import org.seasar.framework.beans.factory.BeanDescFactory;
33  import org.seasar.framework.exception.ResourceNotFoundRuntimeException;
34  import org.seasar.framework.log.Logger;
35  import org.seasar.framework.util.FieldUtil;
36  import org.seasar.framework.util.ResourceUtil;
37  
38  /**
39   * {@link Image} オブジェクトを管理するためのユーティリティクラスです。<br />
40   * <p>
41   * 本クラスは、クラスパス上のリソースとして存在するイメージファイルを読み込み、管理する機能を提供します。</br>
42   * また、本クラスのメソッドに対してリソースのパスを指定する場合、先頭にスラッシュ(/)がついていてもいなくても同じパスとして扱います。</br>
43   * たとえば、<code>&quot;org/seasar/uruma/images/xxxImage.png&quot;</code> と
44   * <code>&quot;/org/seasar/uruma/images/xxxImage.png&quot;</code>
45   * は同じものとして扱います。
46   * </p>
47   * 
48   * @author y-komori
49   */
50  public class ImageManager {
51      private static ImageRegistry imageRegistry = new ImageRegistry();
52  
53      protected static final Logger logger = Logger.getLogger(ImageManager.class);
54  
55      private ImageManager() {
56      }
57  
58      /**
59       * {@link ImageManager} を初期化します。<br />
60       * 
61       * @param display
62       *            本クラスを使用する前に呼び出してください。
63       */
64      public static void init(final Display display) {
65          imageRegistry = new ImageRegistry(display);
66      }
67  
68      /**
69       * 指定されたキーで登録された画像の {@link Image} オブジェクトを返します。<br />
70       * 
71       * @param key
72       *            キー
73       * @return 見つかった {@link Image} オブジェクト。見つからない場合は <code>null</code>。
74       */
75      public static Image getImage(final String key) {
76          return imageRegistry.get(key);
77      }
78  
79      /**
80       * 指定されたキーで登録された画像の {@link ImageDescriptor} オブジェクトを返します。<br />
81       * 
82       * @param key
83       *            キー
84       * @return 見つかった {@link ImageDescriptor} オブジェクト。見つからない場合は <code>null</code>。
85       */
86      public static ImageDescriptor getImageDescriptor(final String key) {
87          return imageRegistry.getDescriptor(key);
88      }
89  
90      /**
91       * <code>path</code> で指定された {@link Image} オブジェクトを検索し、存在しなければクラスパスからロードします。<br />
92       * <p>
93       * 本メソッドでは、まず <code>path</code> をキーと見なしてレジストリから {@link Image}
94       * オブジェクトを検索します。 {@link Image} オブジェクトが見つからない場合、<code>path</code>
95       * で示されるリソースをクラスパスからロードして <code>path</code> をキーとしてレジストリに登録します。<br />
96       * この際、<code>path</code> は <code>/</code>(スラッシュ)で始まっていてもいなくても構いません。</br>
97       * </p>
98       * <dl>
99       * <dt>【例】
100      * <dd> loadImage("icons/app.png");
101      * </dl>
102      * <ul>
103      * <li>まず、レジストリに対して <code>icons/app.png</code> というキーで <code>Image</code>
104      * オブジェクトを検索します。
105      * <li>見つからない場合、クラスパスから <code>icons/app.png</code> というリソースをロードします。
106      * <li>ロードに成功すれば、<code>icons/app.png</code> というキーでレジストリに登録します。
107      * <li>ここで見つからない場合は、{@link ResourceNotFoundRuntimeException} をスローします。
108      * </ul>
109      * 
110      * @param path
111      *            イメージのパス/キー
112      * @return 見つかった {@link Image} オブジェクト
113      * @throws ResourceNotFoundRuntimeException
114      *             指定されたリソースが見つからなかった場合
115      */
116     public static Image loadImage(final String path) {
117         Image image = getImage(path);
118         if (image == null) {
119             image = putImage(path, path);
120         }
121         return image;
122     }
123 
124     /**
125      * <code>path</code> で指定された {@link ImageDescriptor}
126      * オブジェクトを検索し、存在しなければクラスパスからロードします。<br />
127      * <p>
128      * {@link Image} オブジェクトではなく {@link ImageDescriptor} オブジェクトを返すという点を除き、本メソッドは
129      * {@link #loadImage(String)} メソッドと同じです。<br />
130      * 詳細は {@link #loadImage(String)} メソッドの説明をご覧ください。
131      * </p>
132      * 
133      * @param path
134      *            イメージのパス/キー
135      * @return 見つかった {@link ImageDescriptor} オブジェクト
136      * @throws ResourceNotFoundRuntimeException
137      *             指定されたリソースが見つからなかった場合
138      */
139     public static ImageDescriptor loadImageDescriptor(final String path) {
140         ImageDescriptor descriptor = getImageDescriptor(path);
141         if (descriptor == null) {
142             descriptor = putImageDescriptor(path, path);
143         }
144         return descriptor;
145     }
146 
147     /**
148      * {@link Image} オブジェクトを登録します。<br />
149      * <p>
150      * <code>path</code> で示されるリソースをクラスパス上から読み込み、<code>key</code>
151      * で示されるキーでレジストリに登録します。<br />
152      * 既に同じキーで {@link Image} オブジェクトが登録されている場合、上書きします。</br>
153      * </p>
154      * 
155      * @param key
156      *            キー
157      * @param path
158      *            イメージのパス
159      * @return 登録した {@link Image} オブジェクト
160      * @throws ResourceNotFoundRuntimeException
161      *             指定されたリソースが見つからなかった場合
162      */
163     public static Image putImage(final String key, final String path) {
164         checkKey(key);
165 
166         InputStream is = ResourceUtil.getResourceAsStream(normalizePath(path));
167         Image image = new Image(Display.getCurrent(), is);
168         imageRegistry.put(key, image);
169         return image;
170     }
171 
172     /**
173      * {@link ImageData} から生成した {@link Image} オブジェクトを登録します。<br />
174      * <p>
175      * 既に同じキーで {@link Image} オブジェクトが登録されている場合、上書きします。</br>
176      * </p>
177      * 
178      * @param key
179      *            キー
180      * @param imageData
181      *            {@link ImageData} オブジェクト
182      * @return 登録した {@link Image} オブジェクト
183      */
184     public static Image putImage(final String key, final ImageData imageData) {
185         checkKey(key);
186         Image image = new Image(Display.getCurrent(), imageData);
187         imageRegistry.put(key, image);
188         return image;
189     }
190 
191     /**
192      * <code>ImageDescriptor</code> オブジェクトを登録します。<br />
193      * <p>
194      * <code>path</code> で示されるリソースをクラスパス上から読み込み、{@link ImageDescriptor}
195      * オブジェクトとして <code>key</code> で示されるキーでレジストリに登録します。<br />
196      * 既に同じキーで {@link ImageDescriptor} オブジェクトが登録されている場合、上書きします。<br />
197      * </p>
198      * 
199      * @param key
200      *            キー
201      * @param path
202      *            リソースのパス
203      * @return 登録した {@link ImageDescriptor} オブジェクト
204      * @throws ResourceNotFoundRuntimeException
205      *             指定されたリソースが見つからなかった場合
206      */
207     public static ImageDescriptor putImageDescriptor(final String key,
208             final String path) {
209         checkKey(key);
210 
211         URL url = ResourceUtil.getResource(normalizePath(path));
212         ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
213         imageRegistry.put(key, descriptor);
214         return descriptor;
215     }
216 
217     /**
218      * {@link ResourceBundle} からイメージを読み込み、一括登録します。<br />
219      * <p>
220      * 「key=path」の形式で記述されたプロパティファイルを元にした {@link ResourceBundle} から {@link Image}
221      * オブジェクトを一括して読み込みます。
222      * </p>
223      * <p>
224      * 本メソッドではイメージを {@link ImageDescriptor} として登録します。
225      * </p>
226      * 
227      * <p>
228      * コーディング例
229      * </p>
230      * 
231      * <pre>
232      * ResourceBundle imageResources = ResourceBundle.getBundle(&quot;urumaImages&quot;);
233      * ImageManager.loadImages(imageResources);
234      * </pre>
235      * 
236      * @param bundle
237      *            リソースバンドルの参照
238      */
239     public static void loadImages(final ResourceBundle bundle) {
240         Enumeration keys = bundle.getKeys();
241         while (keys.hasMoreElements()) {
242             String key = (String) keys.nextElement();
243             String path = bundle.getString(key);
244             putImageDescriptor(key, path);
245         }
246     }
247 
248     /**
249      * 指定したクラスローダの {@link ResourceBundle} からイメージを読み込み、一括登録します。<br />
250      * <p>
251      * 「key=path」の形式で記述されたプロパティファイルを元にした {@link ResourceBundle} から {@link Image}
252      * オブジェクトを一括して読み込みます。
253      * </p>
254      * <p>
255      * 本メソッドではイメージを {@link ImageDescriptor} として登録します。
256      * </p>
257      * 
258      * @param baseName
259      *            リソースバンドルの基底名
260      * @param loader
261      *            リソースバンドルを読み込むクラスローダ
262      */
263     public static void loadImages(final String baseName,
264             final ClassLoader loader) {
265         ResourceBundle imageResources = ResourceBundle.getBundle(baseName,
266                 Locale.getDefault(), loader);
267         loadImages(imageResources);
268     }
269 
270     /**
271      * {@link ResourceBundle} からイメージを読み込み、一括登録します。<br />
272      * <p>
273      * 「key=path」の形式で記述されたプロパティファイルを元にした {@link ResourceBundle} から {@link Image}
274      * オブジェクトを一括して読み込みます。
275      * </p>
276      * <p>
277      * 本メソッドではイメージを {@link ImageDescriptor} として登録します。
278      * </p>
279      * 
280      * @param baseName
281      *            リソースバンドルの基底名
282      */
283     public static void loadImages(final String baseName) {
284         ResourceBundle imageResources = ResourceBundle.getBundle(baseName);
285         loadImages(imageResources);
286     }
287 
288     /**
289      * 指定されたクラスの定数フィールドに対して、 {@link ImageManager} が 管理するオブジェクトをインジェクションします。</br>
290      * インジェクション対象となるのは、以下の条件を満たすフィールドです。<br />
291      * <p>
292      * <ol>
293      * <li><code>public static</code> な定数フィールドであること
294      * <li>{@link Image} または {@link ImageDescriptor} 型のフィールドであること
295      * </ol>
296      * </p>
297      * 以上の条件を満たすフィールドに対して、フィールド名をキーとして {@link ImageManager} が登録する {@link Image}
298      * または {@link ImageDescriptor} を検索し、見つかればインジェクションを行います。<br />
299      * 見つからなかった場合は、Warning ログを出力します。
300      * <p>
301      * <b>【例】</b><br />
302      * 以下の例では、<code>ImageHolder</code> クラスの フィールド、<code>IMAGE_A</code> と
303      * <code>IMAGE_B</code> に対して、 {@link ImageManager} が管理するオブジェクトの中から、<code>IMAGE_A</code>、<code>IMAGE_B</code>
304      * という名前のキーで登録されたオブジェクトをインジェクションします。
305      * 
306      * <pre>
307      *                           public class ImageHolder() {
308      *                               public static Image IMAGE_A;
309      *                               public static ImageDescriptor IMAGE_B;
310      *                           }
311      * </pre>
312      * <pre>
313      * ImageManager.injectImages(ImageHolder.class);
314      * </pre>
315      * 
316      * </p>
317      * 
318      * @param clazz
319      *            対象クラス
320      */
321     public static void injectImages(final Class clazz) {
322         BeanDesc beanDesc = BeanDescFactory.getBeanDesc(clazz);
323         for (int i = 0; i < beanDesc.getFieldSize(); i++) {
324             Field field = beanDesc.getField(i);
325             String key = field.getName();
326             if (!validateMask(field)) {
327                 continue;
328             }
329 
330             if (isAssignableFrom(Image.class, field)) {
331                 injectField(clazz, field, imageRegistry.get(key));
332             } else if (isAssignableFrom(ImageDescriptor.class, field)) {
333                 injectField(clazz, field, imageRegistry.getDescriptor(key));
334             }
335         }
336     }
337 
338     /**
339      * {@link ImageManager} が管理する {@link ImageRegistry} を破棄します。<br />
340      * <p>
341      * 再び {@link ImageManager} を使用したい場合、{@link #init(Display)} メソッドを呼び出してください。<br />
342      * </p>
343      */
344     public static void dispose() {
345         if (imageRegistry != null) {
346             imageRegistry.dispose();
347         }
348         imageRegistry = null;
349     }
350 
351     protected static void injectField(final Class clazz, final Field field,
352             final Object o) {
353         if (o != null) {
354             FieldUtil.set(field, null, o);
355         }
356     }
357 
358     protected static boolean validateMask(final Field field) {
359         final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
360         final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
361         return (field.getModifiers() & MOD_MASK) == MOD_EXPECTED;
362     }
363 
364     protected static boolean isAssignableFrom(final Class<?> clazz,
365             final Field target) {
366         return clazz.isAssignableFrom(target.getType());
367     }
368 
369     protected static void checkKey(final String key) {
370         if (imageRegistry.get(key) != null) {
371             imageRegistry.remove(key);
372         }
373     }
374 
375     protected static String normalizePath(final String path) {
376         if ((path != null) && (path.startsWith("/"))) {
377             if (path.length() > 1) {
378                 return path.substring(1);
379             }
380 			return "";
381         }
382 		return path;
383     }
384 }