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-2023 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.Collection;
27 import java.util.EnumMap;
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.concurrent.CopyOnWriteArrayList;
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
86  private final Collection<MapImageCacheListener<G, A, R>> listenerList = new CopyOnWriteArrayList<>();
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 
106  private final MapControlListener<G, A, R> mapControlListener = mapControl -> {
107  final MapFile mapFile = mapControl.getMapModel().getMapFile();
108  assert mapFile != null;
109  final File file = mapFile.getFile();
110  updateCaches(file, mapControl, ImageType.ICON);
111  updateCaches(file, mapControl, ImageType.PREVIEW);
112  };
113 
125  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) {
126  this.mapManager = mapManager;
127  this.rendererFactory = rendererFactory;
128  entries.put(ImageType.ICON, new MapImageCacheEntry(cacheFiles, defaultIcon, ImageType.ICON.toString()));
129  entries.put(ImageType.PREVIEW, new MapImageCacheEntry(cacheFiles, defaultPreview, ImageType.PREVIEW.toString()));
130 
131  final MapManagerListener<G, A, R> mapManagerListener = new MapManagerListener<G, A, R>() {
132 
133  @Override
134  public void currentMapChanged(@Nullable final MapControl<G, A, R> mapControl) {
135  // ignore
136  }
137 
138  @Override
139  public void mapCreated(@NotNull final MapControl<G, A, R> mapControl, final boolean interactive) {
140  mapControl.addMapControlListener(mapControlListener);
141  }
142 
143  @Override
144  public void mapClosing(@NotNull final MapControl<G, A, R> mapControl) {
145  // ignore
146  }
147 
153  @Override
154  public void mapClosed(@NotNull final MapControl<G, A, R> mapControl) {
155  mapControl.addMapControlListener(mapControlListener);
156  mapRendererReferences.remove(mapControl);
157  }
158 
159  };
160  mapManager.addMapManagerListener(mapManagerListener);
161  }
162 
167  public void flush(@NotNull final File mapFile) {
168  for (final ImageType imageType : ImageType.values()) {
169  entries.get(imageType).flush(mapFile);
170  }
171  }
172 
179  @Nullable
180  public Image getIcon(@NotNull final File mapFile) {
181  return entries.get(ImageType.ICON).lookupCache(mapFile);
182  }
183 
191  @Nullable
192  public Image getOrCreateIcon(@NotNull final File mapFile) {
193  return getOrCreate(mapFile, ImageType.ICON);
194  }
195 
202  @NotNull
203  public Image getOrCreateIcon(@NotNull final MapControl<G, A, R> mapControl) {
204  return getOrCreate(mapControl, ImageType.ICON);
205  }
206 
213  @Nullable
214  public Image getPreview(@NotNull final File mapFile) {
215  return entries.get(ImageType.PREVIEW).lookupCache(mapFile);
216  }
217 
225  @Nullable
226  public Image getOrCreatePreview(@NotNull final File mapFile) {
227  return getOrCreate(mapFile, ImageType.PREVIEW);
228  }
229 
236  @NotNull
237  public Image getOrCreatePreview(@NotNull final MapControl<G, A, R> mapControl) {
238  return getOrCreate(mapControl, ImageType.PREVIEW);
239  }
240 
248  @Nullable
249  private Image updateCaches(@NotNull final File mapFile, final ImageType imageType) {
250  try {
251  final MapControl<G, A, R> mapControl = mapManager.openMapFile(mapFile, false);
252  try {
253  return updateCaches(mapFile, mapControl, imageType);
254  } finally {
255  mapManager.release(mapControl);
256  }
257  } catch (final IOException ignored) {
258  // ignore: do not update cached images
259  }
260 
261  return entries.get(imageType).getDefaultImage();
262  }
263 
273  @NotNull
274  private Image updateCaches(@Nullable final File mapFile, @NotNull final MapControl<G, A, R> mapControl, final ImageType imageType) {
275  final Image image;
276  //noinspection ErrorNotRethrown
277  try {
278  image = getRenderer(mapControl).getFullImage();
279  } catch (final OutOfMemoryError ignored) {
280  return entries.get(imageType).getDefaultImage();
281  }
282  final Image[] images = new Image[2];
283  images[0] = entries.get(ImageType.ICON).scaleImage(mapFile, image, ICON_WIDTH, ICON_HEIGHT);
284  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);
285 
286  if (mapFile != null) {
287  for (final MapImageCacheListener<G, A, R> listener : listenerList) {
288  listener.iconChanged(mapControl);
289  }
290  }
291 
292  return images[imageType == ImageType.ICON ? 0 : 1];
293  }
294 
301  @NotNull
302  private MapRenderer getRenderer(@NotNull final MapControl<G, A, R> mapControl) {
303  final SoftReference<MapRenderer> mapRendererReference = mapRendererReferences.get(mapControl);
304  final MapRenderer tmpMapRenderer = mapRendererReference == null ? null : mapRendererReference.get();
305  final MapRenderer mapRenderer;
306  if (tmpMapRenderer == null) {
307  mapRenderer = rendererFactory.newSimpleMapRenderer(mapControl.getMapModel());
308  mapRendererReferences.put(mapControl, new SoftReference<>(mapRenderer));
309  } else {
310  mapRenderer = tmpMapRenderer;
311  }
312  return mapRenderer;
313  }
314 
319  public void addMapImageCacheListener(@NotNull final MapImageCacheListener<G, A, R> listener) {
320  listenerList.add(listener);
321  }
322 
327  public void removeMapImageCacheListener(@NotNull final MapImageCacheListener<G, A, R> listener) {
328  listenerList.remove(listener);
329  }
330 
338  @NotNull
339  private Image getOrCreate(@NotNull final MapControl<G, A, R> mapControl, @NotNull final ImageType imageType) {
340  final MapFile mapFile = mapControl.getMapModel().getMapFile();
341  if (mapFile != null) {
342  final Image image = entries.get(imageType).lookupCache(mapFile.getFile());
343  if (image != null) {
344  return image;
345  }
346  }
347 
348  return updateCaches(mapFile == null ? null : mapFile.getFile(), mapControl, imageType);
349  }
350 
359  @Nullable
360  private Image getOrCreate(@NotNull final File mapFile, @NotNull final ImageType imageType) {
361  if (mapFile.isDirectory()) {
362  return null;
363  }
364 
365  final Image image = entries.get(imageType).lookupCache(mapFile);
366  return image == null ? updateCaches(mapFile, imageType) : image;
367  }
368 
369 }
net.sf.gridarta.model.mapmanager
Definition: AbstractMapManager.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCache.entries
final Map< ImageType, MapImageCacheEntry > entries
The cache entries.
Definition: MapImageCache.java:93
net.sf.gridarta.model.mapmanager.MapManager
A MapManager manages all opened maps.
Definition: MapManager.java:37
net.sf.gridarta.gui.mapimagecache.MapImageCache.getOrCreateIcon
Image getOrCreateIcon(@NotNull final MapControl< G, A, R > mapControl)
Returns an icon Image for a given map.
Definition: MapImageCache.java:203
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.gui.mapimagecache.MapImageCache.getOrCreatePreview
Image getOrCreatePreview(@NotNull final MapControl< G, A, R > mapControl)
Returns a preview Image for a given map.
Definition: MapImageCache.java:237
net.sf
net.sf.gridarta.model.mapmanager.MapManagerListener
Interface for listeners listening to MapManager changes.
Definition: MapManagerListener.java:42
net.sf.gridarta.gui.map.renderer.RendererFactory.newSimpleMapRenderer
MapRenderer newSimpleMapRenderer(@NotNull MapModel< G, A, R > mapModel)
Creates a new map renderer instance which paints only squares but no grid, cursor,...
net.sf.gridarta.model.mapmodel
Definition: AboveFloorInsertionMode.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCache.mapRendererReferences
final Map< MapControl< G, A, R >, SoftReference< MapRenderer > > mapRendererReferences
Maps MapControl instance to MapRenderer which is only used to get images.
Definition: MapImageCache.java:100
net.sf.gridarta.gui.map.renderer
Definition: AbstractIsoMapRenderer.java:20
net.sf.gridarta.model.mapmanager.MapManager.addMapManagerListener
void addMapManagerListener(@NotNull MapManagerListener< G, A, R > listener)
Adds a MapManagerListener to be notified.
net.sf.gridarta.model.archetype
Definition: AbstractArchetype.java:20
net.sf.gridarta.model.gameobject.GameObject
Reflects a game object (object on a map).
Definition: GameObject.java:36
net.sf.gridarta.model.mapcontrol
Definition: DefaultMapControl.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCache.ICON_HEIGHT
static final int ICON_HEIGHT
The height of icons in pixels.
Definition: MapImageCache.java:63
net.sf.gridarta.gui.mapimagecache.ImageType.PREVIEW
PREVIEW
The preview is a large thumbnail.
Definition: ImageType.java:36
net.sf.gridarta.gui
Graphical User Interface of Gridarta.
net.sf.gridarta.gui.mapimagecache.MapImageCache.getOrCreate
Image getOrCreate(@NotNull final File mapFile, @NotNull final ImageType imageType)
Returns a preview Image for a given map file.
Definition: MapImageCache.java:360
net.sf.gridarta.gui.mapimagecache.MapImageCache.getIcon
Image getIcon(@NotNull final File mapFile)
Returns the icon Image for a given map file.
Definition: MapImageCache.java:180
net.sf.gridarta.gui.mapimagecache.MapImageCache
Caches icon and preview images for map files.
Definition: MapImageCache.java:53
net.sf.gridarta.model.gameobject
GameObjects are the objects based on Archetypes found on maps.
Definition: AbstractGameObject.java:20
net
net.sf.gridarta.gui.mapimagecache.MapImageCache.getOrCreateIcon
Image getOrCreateIcon(@NotNull final File mapFile)
Returns an icon Image for a given map file.
Definition: MapImageCache.java:192
net.sf.gridarta.gui.mapimagecache.MapImageCache.removeMapImageCacheListener
void removeMapImageCacheListener(@NotNull final MapImageCacheListener< G, A, R > listener)
Removes a MapControlListener to be notified.
Definition: MapImageCache.java:327
net.sf.gridarta.gui.mapimagecache.MapImageCache.rendererFactory
final RendererFactory< G, A, R > rendererFactory
The RendererFactory for creating renderers.
Definition: MapImageCache.java:80
net.sf.gridarta.gui.mapimagecache.MapImageCache.flush
void flush(@NotNull final File mapFile)
Removes the cached images for a map file.
Definition: MapImageCache.java:167
net.sf.gridarta.gui.mapimagecache.MapImageCache.mapControlListener
final MapControlListener< G, A, R > mapControlListener
The MapControlListener attached to all MapControls.
Definition: MapImageCache.java:106
net.sf.gridarta.gui.mapimagecache.MapImageCache.listenerList
final Collection< MapImageCacheListener< G, A, R > > listenerList
The registered event listeners.
Definition: MapImageCache.java:86
net.sf.gridarta.model.maparchobject.MapArchObject
Interface for MapArchObjects.
Definition: MapArchObject.java:40
net.sf.gridarta.gui.mapimagecache.MapImageCache.updateCaches
Image updateCaches(@NotNull final File mapFile, final ImageType imageType)
Updates the cached icon and preview Images for one map file.
Definition: MapImageCache.java:249
net.sf.gridarta.gui.mapimagecache.MapImageCache.getOrCreatePreview
Image getOrCreatePreview(@NotNull final File mapFile)
Returns a preview Image for a given map file.
Definition: MapImageCache.java:226
net.sf.gridarta.model.mapmodel.MapFile.getFile
File getFile()
Returns a File for this map file.
Definition: MapFile.java:102
net.sf.gridarta.model.mapmanager.MapManager.openMapFile
MapControl< G, A, R > openMapFile(@NotNull MapFile mapFile, boolean interactive)
Loads a map file.
net.sf.gridarta.gui.mapimagecache.MapImageCacheListener< G, A, R >
net.sf.gridarta.gui.mapimagecache.MapImageCache.MapImageCache
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.
Definition: MapImageCache.java:125
net.sf.gridarta.gui.mapimagecache.MapImageCache.addMapImageCacheListener
void addMapImageCacheListener(@NotNull final MapImageCacheListener< G, A, R > listener)
Adds a MapImageCacheListener to be notified.
Definition: MapImageCache.java:319
net.sf.gridarta.gui.mapimagecache.MapImageCache.mapManager
final MapManager< G, A, R > mapManager
The MapManager for loading maps.
Definition: MapImageCache.java:74
net.sf.gridarta.model.mapmodel.MapFile
The location of a map file with a map directory.
Definition: MapFile.java:31
net.sf.gridarta.model.io
Reading and writing of maps, handling of paths.
Definition: AbstractAnimationObjectsReader.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCache.PREVIEW_SCALE
static final int PREVIEW_SCALE
The scale factor for preview images.
Definition: MapImageCache.java:68
net.sf.gridarta.model.mapmanager.MapManager.release
void release(@NotNull MapControl< G, A, R > mapControl)
Releases a MapControl instance.
net.sf.gridarta.gui.mapimagecache.ImageType
The types of images that are cached.
Definition: ImageType.java:26
net.sf.gridarta.gui.mapimagecache.MapImageCache.getRenderer
MapRenderer getRenderer(@NotNull final MapControl< G, A, R > mapControl)
Returns a MapRenderer for a map.
Definition: MapImageCache.java:302
net.sf.gridarta.gui.mapimagecache.MapImageCache.getPreview
Image getPreview(@NotNull final File mapFile)
Returns a preview Image for a given map file.
Definition: MapImageCache.java:214
net.sf.gridarta.model
net.sf.gridarta.model.archetype.Archetype
Reflects an Archetype.
Definition: Archetype.java:41
net.sf.gridarta.gui.mapimagecache.MapImageCache.getOrCreate
Image getOrCreate(@NotNull final MapControl< G, A, R > mapControl, @NotNull final ImageType imageType)
Returns an icon or preview Image for a given map.
Definition: MapImageCache.java:339
net.sf.gridarta.gui.mapimagecache.MapImageCache.ICON_WIDTH
static final int ICON_WIDTH
The width of icons in pixels.
Definition: MapImageCache.java:58
net.sf.gridarta.gui.map.renderer.RendererFactory
Factory for creating MapRenderer instances.
Definition: RendererFactory.java:33
net.sf.gridarta.gui.map
Base classes for rendering maps.
Definition: AbstractPerMapDialogManager.java:20
net.sf.gridarta.gui.mapimagecache.MapImageCacheEntry
An image cache entry for one ImageType.
Definition: MapImageCacheEntry.java:42
net.sf.gridarta.model.mapcontrol.MapControl
Currently nothing more than a marker interface for unification.
Definition: MapControl.java:35
net.sf.gridarta.model.mapcontrol.MapControlListener
Interface for listeners listening on changes in MapControl instances.
Definition: MapControlListener.java:33
net.sf.gridarta.gui.mapimagecache.ImageType.ICON
ICON
The icon is a small thumbnail usable as icon in file browsers.
Definition: ImageType.java:31
net.sf.gridarta.model.maparchobject
Definition: AbstractMapArchObject.java:20
net.sf.gridarta.gui.map.renderer.MapRenderer.getFullImage
BufferedImage getFullImage()
Returns an image of the entire map view.
net.sf.gridarta.model.io.CacheFiles
Creates derived files for caching files.
Definition: CacheFiles.java:30
net.sf.gridarta.gui.mapimagecache.MapImageCache.updateCaches
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.
Definition: MapImageCache.java:274
net.sf.gridarta.gui.map.renderer.MapRenderer
Common interface for renderers of map control instances.
Definition: MapRenderer.java:36