Gridarta Editor
MapImageCache.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.gui.mapimagecache;
21 
22 import java.awt.Image;
23 import java.io.File;
24 import java.io.IOException;
25 import java.lang.ref.SoftReference;
26 import java.util.EnumMap;
27 import java.util.HashMap;
28 import java.util.Map;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
44 
53 public class MapImageCache<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> {
54 
58  private static final int ICON_WIDTH = 48;
59 
63  private static final int ICON_HEIGHT = 23;
64 
68  private static final int PREVIEW_SCALE = 8;
69 
73  @NotNull
75 
79  @NotNull
81 
85  @NotNull
87 
92  @NotNull
93  private final Map<ImageType, MapImageCacheEntry> entries = new EnumMap<>(ImageType.class);
94 
99  @NotNull
100  private final Map<MapControl<G, A, R>, SoftReference<MapRenderer>> mapRendererReferences = new HashMap<>();
101 
107 
108  @Override
109  public void saved(@NotNull final DefaultMapControl<G, A, R> mapControl) {
110  final MapFile mapFile = mapControl.getMapModel().getMapFile();
111  assert mapFile != null;
112  final File file = mapFile.getFile();
113  updateCaches(file, mapControl, ImageType.ICON);
114  updateCaches(file, mapControl, ImageType.PREVIEW);
115  }
116 
117  };
118 
130  public MapImageCache(@NotNull final MapManager<G, A, R> mapManager, @NotNull final Image defaultIcon, @NotNull final Image defaultPreview, @NotNull final RendererFactory<G, A, R> rendererFactory, @NotNull final CacheFiles cacheFiles) {
131  this.mapManager = mapManager;
132  this.rendererFactory = rendererFactory;
133  entries.put(ImageType.ICON, new MapImageCacheEntry(cacheFiles, defaultIcon, ImageType.ICON.toString()));
134  entries.put(ImageType.PREVIEW, new MapImageCacheEntry(cacheFiles, defaultPreview, ImageType.PREVIEW.toString()));
135 
136  final MapManagerListener<G, A, R> mapManagerListener = new MapManagerListener<G, A, R>() {
137 
138  @Override
139  public void currentMapChanged(@Nullable final MapControl<G, A, R> mapControl) {
140  // ignore
141  }
142 
143  @Override
144  public void mapCreated(@NotNull final MapControl<G, A, R> mapControl, final boolean interactive) {
145  mapControl.addMapControlListener(mapControlListener);
146  }
147 
148  @Override
149  public void mapClosing(@NotNull final MapControl<G, A, R> mapControl) {
150  // ignore
151  }
152 
158  @Override
159  public void mapClosed(@NotNull final MapControl<G, A, R> mapControl) {
160  mapControl.addMapControlListener(mapControlListener);
161  mapRendererReferences.remove(mapControl);
162  }
163 
164  };
165  mapManager.addMapManagerListener(mapManagerListener);
166  }
167 
172  public void flush(@NotNull final File mapFile) {
173  for (final ImageType imageType : ImageType.values()) {
174  entries.get(imageType).flush(mapFile);
175  }
176  }
177 
184  @Nullable
185  public Image getIcon(@NotNull final File mapFile) {
186  return entries.get(ImageType.ICON).lookupCache(mapFile);
187  }
188 
196  @Nullable
197  public Image getOrCreateIcon(@NotNull final File mapFile) {
198  return getOrCreate(mapFile, ImageType.ICON);
199  }
200 
207  @NotNull
208  public Image getOrCreateIcon(@NotNull final MapControl<G, A, R> mapControl) {
209  return getOrCreate(mapControl, ImageType.ICON);
210  }
211 
218  @Nullable
219  public Image getPreview(@NotNull final File mapFile) {
220  return entries.get(ImageType.PREVIEW).lookupCache(mapFile);
221  }
222 
230  @Nullable
231  public Image getOrCreatePreview(@NotNull final File mapFile) {
232  return getOrCreate(mapFile, ImageType.PREVIEW);
233  }
234 
241  @NotNull
242  public Image getOrCreatePreview(@NotNull final MapControl<G, A, R> mapControl) {
243  return getOrCreate(mapControl, ImageType.PREVIEW);
244  }
245 
253  @Nullable
254  private Image updateCaches(@NotNull final File mapFile, final ImageType imageType) {
255  try {
256  final MapControl<G, A, R> mapControl = mapManager.openMapFile(mapFile, false);
257  try {
258  return updateCaches(mapFile, mapControl, imageType);
259  } finally {
260  mapManager.release(mapControl);
261  }
262  } catch (final IOException ignored) {
263  // ignore: do not update cached images
264  }
265 
266  return entries.get(imageType).getDefaultImage();
267  }
268 
278  @NotNull
279  private Image updateCaches(@Nullable final File mapFile, @NotNull final MapControl<G, A, R> mapControl, final ImageType imageType) {
280  final Image image;
281  //noinspection ErrorNotRethrown
282  try {
283  image = getRenderer(mapControl).getFullImage();
284  } catch (final OutOfMemoryError ignored) {
285  return entries.get(imageType).getDefaultImage();
286  }
287  final Image[] images = new Image[2];
288  images[0] = entries.get(ImageType.ICON).scaleImage(mapFile, image, ICON_WIDTH, ICON_HEIGHT);
289  images[1] = entries.get(ImageType.PREVIEW).scaleImage(mapFile, image, (image.getWidth(null) + PREVIEW_SCALE - 1) / PREVIEW_SCALE, (image.getHeight(null) + PREVIEW_SCALE - 1) / PREVIEW_SCALE);
290 
291  if (mapFile != null) {
292  for (final MapImageCacheListener<G, A, R> listener : listenerList.getListeners()) {
293  listener.iconChanged(mapControl);
294  }
295  }
296 
297  return images[imageType == ImageType.ICON ? 0 : 1];
298  }
299 
306  @NotNull
307  private MapRenderer getRenderer(@NotNull final MapControl<G, A, R> mapControl) {
308  final SoftReference<MapRenderer> mapRendererReference = mapRendererReferences.get(mapControl);
309  final MapRenderer tmpMapRenderer = mapRendererReference == null ? null : mapRendererReference.get();
310  final MapRenderer mapRenderer;
311  if (tmpMapRenderer == null) {
312  mapRenderer = rendererFactory.newSimpleMapRenderer(mapControl.getMapModel());
313  mapRendererReferences.put(mapControl, new SoftReference<>(mapRenderer));
314  } else {
315  mapRenderer = tmpMapRenderer;
316  }
317  return mapRenderer;
318  }
319 
324  public void addMapImageCacheListener(@NotNull final MapImageCacheListener<G, A, R> listener) {
325  listenerList.add(listener);
326  }
327 
332  public void removeMapImageCacheListener(@NotNull final MapImageCacheListener<G, A, R> listener) {
333  listenerList.remove(listener);
334  }
335 
343  @NotNull
344  private Image getOrCreate(@NotNull final MapControl<G, A, R> mapControl, @NotNull final ImageType imageType) {
345  final MapFile mapFile = mapControl.getMapModel().getMapFile();
346  if (mapFile != null) {
347  final Image image = entries.get(imageType).lookupCache(mapFile.getFile());
348  if (image != null) {
349  return image;
350  }
351  }
352 
353  return updateCaches(mapFile == null ? null : mapFile.getFile(), mapControl, imageType);
354  }
355 
364  @Nullable
365  private Image getOrCreate(@NotNull final File mapFile, @NotNull final ImageType imageType) {
366  if (mapFile.isDirectory()) {
367  return null;
368  }
369 
370  final Image image = entries.get(imageType).lookupCache(mapFile);
371  if (image != null) {
372  return image;
373  }
374 
375  return updateCaches(mapFile, imageType);
376  }
377 
378 }
void addMapImageCacheListener(@NotNull final MapImageCacheListener< G, A, R > listener)
Adds a MapImageCacheListener to be notified.
Image getOrCreateIcon(@NotNull final File mapFile)
Returns an icon Image for a given map file.
Image updateCaches(@Nullable final File mapFile, @NotNull final MapControl< G, A, R > mapControl, final ImageType imageType)
Updates the cached icon and preview Images for one map file.
A MapManager manages all opened maps.
Definition: MapManager.java:37
void release(@NotNull MapControl< G, A, R > mapControl)
Releases a MapControl instance.
Graphical User Interface of Gridarta.
T [] getListeners()
Returns an array of all the listeners.
Reading and writing of maps, handling of paths.
BufferedImage getFullImage()
Returns an image of the entire map view.
ICON
The icon is a small thumbnail usable as icon in file browsers.
Definition: ImageType.java:31
The preview is a large thumbnail.
Definition: ImageType.java:36
Creates derived files for caching files.
Definition: CacheFiles.java:30
Image getOrCreatePreview(@NotNull final MapControl< G, A, R > mapControl)
Returns a preview Image for a given map.
Image getOrCreate(@NotNull final File mapFile, @NotNull final ImageType imageType)
Returns a preview Image for a given map file.
MapRenderer newSimpleMapRenderer(@NotNull MapModel< G, A, R > mapModel)
Creates a new map renderer instance which paints only squares but no grid, cursor, selection, or errors.
Image getPreview(@NotNull final File mapFile)
Returns a preview Image for a given map file.
Base package of all Gridarta classes.
final MapManager< G, A, R > mapManager
The MapManager for loading maps.
Reflects a game object (object on a map).
Definition: GameObject.java:36
Interface for listeners listening to MapManager changes.
static final int ICON_HEIGHT
The height of icons in pixels.
void remove(@NotNull final T listener)
Removes a listener.
Interface for listeners listening on changes in MapControl instances.
static final int ICON_WIDTH
The width of icons in pixels.
void flush(@NotNull final File mapFile)
Removes the cached images for a map file.
GameObjects are the objects based on Archetypes found on maps.
void add(@NotNull final T listener)
Adds a listener.
Image getOrCreatePreview(@NotNull final File mapFile)
Returns a preview Image for a given map file.
Caches icon and preview images for map files.
An image cache entry for one ImageType.
final Map< MapControl< G, A, R >, SoftReference< MapRenderer > > mapRendererReferences
Maps MapControl instance to MapRenderer which is only used to get images.
Image updateCaches(@NotNull final File mapFile, final ImageType imageType)
Updates the cached icon and preview Images for one map file.
Base classes for rendering maps.
Image getOrCreate(@NotNull final MapControl< G, A, R > mapControl, @NotNull final ImageType imageType)
Returns an icon or preview Image for a given map.
Factory for creating MapRenderer instances.
final Map< ImageType, MapImageCacheEntry > entries
The cache entries.
Type-safe version of EventListenerList.
final EventListenerList2< MapImageCacheListener< G, A, R > > listenerList
The registered event listeners.
The types of images that are cached.
Definition: ImageType.java:26
MapImageCache(@NotNull final MapManager< G, A, R > mapManager, @NotNull final Image defaultIcon, @NotNull final Image defaultPreview, @NotNull final RendererFactory< G, A, R > rendererFactory, @NotNull final CacheFiles cacheFiles)
Creates a new instance.
Image getIcon(@NotNull final File mapFile)
Returns the icon Image for a given map file.
Currently nothing more than a marker interface for unification.
Definition: MapControl.java:35
final RendererFactory< G, A, R > rendererFactory
The RendererFactory for creating renderers.
File getFile()
Returns a File for this map file.
Definition: MapFile.java:102
MapRenderer getRenderer(@NotNull final MapControl< G, A, R > mapControl)
Returns a MapRenderer for a map.
void removeMapImageCacheListener(@NotNull final MapImageCacheListener< G, A, R > listener)
Removes a MapControlListener to be notified.
Common interface for renderers of map control instances.
Interface for listeners interested in MapImageCache related events.
MapControl< G, A, R > openMapFile(@NotNull MapFile mapFile, boolean interactive)
Loads a map file.
static final int PREVIEW_SCALE
The scale factor for preview images.
The location of a map file with a map directory.
Definition: MapFile.java:31
final MapControlListener< G, A, R > mapControlListener
The MapControlListener attached to all MapControls.
Image getOrCreateIcon(@NotNull final MapControl< G, A, R > mapControl)
Returns an icon Image for a given map.