Im folgenden soll beschrieben werden, wie man eine Icon Bibliothek erstellt, bei der die Definition der Image Konstanten (API) und die Bereitstellung der konkreten Icons (Implementierung) getrennt ist.
Dieser Ansatz eignet sich sowohl für die Erstellung logischer-, als auch für die Erstellung konkreter Icon Bibliotheken. Die Trennung könnte wie folgt motiviert sein:
Aufteilung API und Implementierung bei der Erstellung einer Widget Bibliothek: Man möchte die API und die Implementierung in unterschiedliche Module packen, eventuell weil es mehrere Implementierungen gibt. Dann gehört die Icon Konstante zur API, das konkrete Icon zur Implementierung.
Einsparung von Resourcen im ausgelieferten Produkt: Eine Icon API beinhaltet sehr viele Icons einer großer Icon Sammlung. Mehrere Produkte verwenden diese Icon API, welche nur Konstanten enthält, um einen schnellen Zugriff auf die möglichen Icons zu haben. Für ein konkretes Produkt wird dann ein konkretes Plugin erstellt, welches nur die Icons registriert, welche in dem Produkt tatsächlich verwendet werden. Die Menge der verwendeten Icons und somit auch das Plugin könnte man mit einem Tool erstellen (Source Code Generierung).
Das folgende Beispiel zeigt die Definition der Icons für eine Audio Player Widget Bibliothek.
1 public enum AudioIcons implements IImageConstant { 2 3 PLAY, 4 STOP, 5 PAUSE, 6 FORWARD, 7 REWIND, 8 9 NEXT, 10 PREVIOUS, 11 FIRST, 12 LAST, 13 14 MUTED, 15 NOT_MUTED, 16 17 LOUDSPEAKER, 18 EDIT_AUDIO_SETTINGS 19 20 }
Die Icon Konstanten können dann für das Default Setup der Widgets und / oder innerhalb der Implementierung verwendet werden.
Die folgende Klasse verwendet die Klasse
AbstractResourceImageInitializer
für die Registrierung der konkreten Icons:
1 package org.mycompany.audio.impl;
2
3 import org.jowidgets.common.image.IImageRegistry;
4 import org.jowidgets.tools.image.AbstractResourceImageInitializer;
5
6 public final class AudioIconsInitializer extends AbstractResourceImageInitializer {
7
8 public AudioIconsInitializer(final IImageRegistry registry) {
9 super(AudioIconsInitializer.class, registry, "org/mycompany/audio/impl/icons/");
10 }
11
12 @Override
13 public void doRegistration() {
14 registerResourceImage(AudioIcons.PLAY, "play.png");
15 registerResourceImage(AudioIcons.STOP, "stop.png");
16 registerResourceImage(AudioIcons.PAUSE, "pause.png");
17 registerResourceImage(AudioIcons.FORWARD, "forward.png");
18 registerResourceImage(AudioIcons.REWIND, "rewind.png");
19
20 registerResourceImage(AudioIcons.NEXT, "next.png");
21 registerResourceImage(AudioIcons.PREVIOUS, "previous.png");
22 registerResourceImage(AudioIcons.FIRST, "first.png");
23 registerResourceImage(AudioIcons.LAST, "last.png");
24
25 registerResourceImage(AudioIcons.MUTED, "muted.png");
26 registerResourceImage(AudioIcons.NOT_MUTED, "not_muted.png");
27
28 registerResourceImage(AudioIcons.LOUDSPEAKER, "loudspeaker.png");
29 registerResourceImage(AudioIcons.EDIT_AUDIO_SETTINGS, "edit_audio_settings.png");
30
31 //do this, if your are assuming that this initializer should initialize all icons
32 checkEnumAvailability(AudioIcons.class);
33 }
34
35 }
Der Test in Zeile 32 ist optional und würde für den Fall, dass
man z.B. vergessen hätte, ein Icon zu registrieren, eine
IllegalStateException
werfen. Wenn man zum
Beispiel die Konstanten der Bibliothek erweitert, und die
konkrete Registrierung vergisst, oder z.B. aus Versehen zwei
mal den gleichen key
für unterschiedliche
Icons verwendet, tritt der Fehler bereits beim Starten der
Applikation auf, was z.B. für einen
Smoketest hilfreich ist, und nicht erst
später, wenn das fehlende Icon verwendet wird.
Die folgende Abbildung zeigt die zugehörigen Icon Dateien innerhalb der Resourcen der Implementierung:
Um sicher zu Stellen, dass die Icons vor der ersten Verwendung
registriert sind, wird empfohlen, die Registrierung innerhalb
eines Toolkit
Interceptors durchzuführen. Das folgende Beispiel nutzt
dazu die abstrakte Klasse
AbstractToolkitInterceptorHolder
:
1 package org.mycompany.audio.impl; 2 3 import org.jowidgets.api.toolkit.IToolkit; 4 import org.jowidgets.api.toolkit.IToolkitInterceptor; 5 import org.jowidgets.tools.toolkit.AbstractToolkitInterceptorHolder; 6 7 public final class AudioIconsInitializerToolkitInterceptor 8 extends AbstractToolkitInterceptorHolder { 9 10 @Override 11 protected IToolkitInterceptor createToolkitInterceptor() { 12 return new IToolkitInterceptor() { 13 @Override 14 public void onToolkitCreate(final IToolkit toolkit) { 15 final AudioIconsInitializer initializer 16 = new AudioIconsInitializer(toolkit.getImageRegistry()); 17 initializer.doRegistration(); 18 } 19 }; 20 } 21 22 }
Um diesen mit Hilfe des Java
ServiceLoader
Mechanismus zu registrieren, kann man unter
META-INF/services
eine Datei mit dem Namen
org.jowidgets.api.toolkit.IToolkitInterceptorHolder
und dem Inhalt:
org.jowidgets.helloworld.common.AudioIconsInitializerToolkitInterceptor
ablegen. Die folgende Abbildung soll das verdeutlichen:
Dadurch werden die Icons automatisch registriert, wenn man das
Modul org.mycompany.audio.impl
im Classpath
hat, und zwar bevor das jowidgets Toolkit verwendet wird, da
der Interceptor bei der Erzeugung des Toolkit ausgeführt wird.