]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.maps/src/org/simantics/maps/tile/TileCache.java
Share some projects for Simantics District
[simantics/district.git] / org.simantics.district.maps / src / org / simantics / maps / tile / TileCache.java
diff --git a/org.simantics.district.maps/src/org/simantics/maps/tile/TileCache.java b/org.simantics.district.maps/src/org/simantics/maps/tile/TileCache.java
new file mode 100644 (file)
index 0000000..9f58193
--- /dev/null
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.maps.tile;
+
+import java.awt.Image;
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class TileCache implements ITileListener {
+
+    public static class LevelCache {
+        /**
+         * Allow collection of tile images when under memory pressure.
+         */
+        private Map<TileKey, SoftReference<Image>> cache = new HashMap<TileKey, SoftReference<Image>>();
+
+        public Image get(TileKey key) {
+            SoftReference<Image> ref = cache.get(key);
+            if (ref == null)
+                return null;
+            return ref.get();
+        }
+
+        public void put(TileKey key, Image value) {
+            cache.put(key, new SoftReference<Image>(value));
+        }
+
+        public void remove(TileKey key) {
+            cache.remove(key);
+        }
+    }
+
+    private final ITileJobQueue      job;
+    private Map<Integer, LevelCache> levels = new HashMap<Integer, LevelCache>();
+    private List<ITileListener>      tileListeners = new ArrayList<ITileListener>();
+
+    public TileCache(ITileJobQueue job) {
+        this.job = job;
+    }
+
+    public void addTileListener(ITileListener l) {
+        tileListeners.add(l);
+    }
+
+    public void removeTileListener(ITileListener l) {
+        tileListeners.remove(l);
+    }
+
+    private LevelCache getLevel(int l, boolean create) {
+        synchronized (levels) {
+            LevelCache level = levels.get(l);
+            if (level == null && create) {
+                level = new LevelCache();
+                levels.put(l, level);
+            }
+            return level;
+        }
+    }
+
+    /**
+     * @param key
+     * @return <code>null</code> to signify that the requested tile was not
+     *         cached and a background request has been scheduled for the tile.
+     */
+    public Image get(final TileKey key) {
+        LevelCache level = getLevel(key.getLevel(), true);
+        Image image = level.get(key);
+        if (image == null) {
+               job.addJob(key, this);
+        }
+        return image;
+    }
+
+    /**
+     * Take a peek into the cache to see if there is an image readily available
+     * for the requested tile.
+     * 
+     * @param key the key of the requested tile
+     * @return <code>null</code> if there was no image in the cache
+     */
+    public Image peek(final TileKey key) {
+        LevelCache level = getLevel(key.getLevel(), false);
+        if (level == null)
+            return null;
+        synchronized (level) {
+            return level.get(key);
+        }
+    }
+
+    /**
+     * Flush the specified tile from the cache.
+     * 
+     * @param key
+     */
+    public synchronized void flush(final TileKey key) {
+        LevelCache level = getLevel(key.getLevel(), false);
+        if (level != null) {
+            synchronized (level) {
+                level.remove(key);
+            }
+        }
+    }
+
+    /**
+     * Removes queries from the job queue that do not pass the specified filter.
+     */
+    public void filterJobQueue(IFilter<TileKey> filter) {
+        job.filterQueries(filter);
+    }
+
+       @Override
+       public void tileCanceled(TileKey key) {
+        for (ITileListener l : tileListeners) {
+            l.tileCanceled(key);
+        }
+       }
+
+       @Override
+       public void tileFailed(TileKey key, Throwable e) {
+        for (ITileListener l : tileListeners) {
+            l.tileFailed(key, e);
+        }
+       }
+
+       @Override
+       public void tileUpdated(TileKey key, Image image) {
+        LevelCache level = getLevel(key.getLevel(), true);
+        synchronized (level) {
+            level.put(key, image);
+        }
+       
+        for (ITileListener l : tileListeners) {
+            l.tileUpdated(key, image);
+        }
+       }
+
+}