/* * jMemorize - Learning made easy (and fun) - A Leitner flashcards tool * Copyright(C) 2004-2008 Riad Djemili and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package jmemorize.core; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.ImageIcon; public class ImageRepository { private static final int MAX_CACHED_IMAGES = 10; public static final String IMG_ID_PREFIX = "::"; private static ImageRepository m_instance; private Map<String, ImageItem> m_imageMap = new HashMap<String, ImageItem>(); private LinkedList<ImageIcon> m_imageCache = new LinkedList<ImageIcon>(); private static final Pattern FILE_PATTERN = Pattern.compile("(.*)_(\\d+)"); public class ImageItem { private String m_sourceFile; private byte[] m_bytes; private String m_id; public ImageItem(InputStream in, String filename) throws IOException { m_sourceFile = filename; m_id = createId(filename); m_bytes = readFile(in); } public ImageIcon getImage() { ImageIcon image = new ImageIcon(m_bytes); image.setDescription(IMG_ID_PREFIX + m_id); return image; } public String getId() { return m_id; } public String getFile() { return m_sourceFile; } public byte[] getBytes() { return m_bytes; } @Override public String toString() { return m_id; } private String createId(String filename) { int dotPos = filename.lastIndexOf("."); String extension = filename.substring(dotPos); String purename = filename.substring(0, dotPos); while (getKeys().contains(purename + extension)) { int num = 0; Matcher m = FILE_PATTERN.matcher(purename); if (m.matches() && m.groupCount() == 2) { num = Integer.valueOf(m.group(2)); num++; purename = m.group(1); } purename = purename + "_" + num; } return purename + extension; } private byte[] readFile(InputStream in) throws IOException { ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int numRead = 0; while ((numRead = in.read(bytes, 0, bytes.length)) >= 0) { bytesOut.write(bytes, 0, numRead); } return bytesOut.toByteArray(); } } // TODO remove singleton pattern and make this referenced from lesson public static ImageRepository getInstance() { if (m_instance == null) m_instance = new ImageRepository(); return m_instance; } public Set<String> getKeys() { return m_imageMap.keySet(); } public Collection<ImageItem> getImageItems() // TODO dont give imageItem to outside { return m_imageMap.values(); } public ImageIcon getImage(String imageId) { for (ImageIcon icon : m_imageCache) { if (equals(icon, imageId)) { m_imageCache.remove(icon); m_imageCache.addFirst(icon); return icon; } } ImageItem imageItem = m_imageMap.get(imageId); if (imageItem == null) return null; ImageIcon icon = imageItem.getImage(); m_imageCache.addFirst(icon); if (m_imageCache.size() > MAX_CACHED_IMAGES) // HACK check for memory usage instead m_imageCache.removeLast(); return icon; } public String addImage(InputStream in, String filename) throws IOException { // TOOD check if image already in our map // for (ImageItem item : m_imageMap.values()) // { // if (item.getFile().equals(filename)) // return item.getId(); // } ImageItem item = new ImageItem(in, filename); String id = item.getId(); m_imageMap.put(id, item); return id; } public String addImage(ImageIcon icon) throws IOException { String description = icon.getDescription(); String id = ""; if (description.startsWith(IMG_ID_PREFIX)) { id = description.substring(IMG_ID_PREFIX.length()); } else { InputStream in; String name = ""; try { URL url = new URL(description); name = new File(url.getPath()).getName(); in = url.openStream(); } catch (MalformedURLException ex) { name = new File(description).getName(); in = new FileInputStream(description); // fallthrough expected } id = addImage(in, name); icon.setDescription(IMG_ID_PREFIX + id); } return id; } /** * Converts the given list of image icons into a list of image IDs. This is * done by using the description field of ImageIcon. If the image icon was * already loaded from the image repository, the description will begin with * IMG_ID_PREFIX, otherwise it will be a new image that wasn't added to the * repository yet. */ public List<String> addImages(List<ImageIcon> images) { List<String> imageIDs = new LinkedList<String>(); for (ImageIcon icon : images) { try { imageIDs.add(addImage(icon)); } catch (IOException e) { Main.logThrowable("could not convert image to image-id", e); } } return imageIDs; } /** * Retains all images with given IDs. All other images are removed. */ public void retain(Set<String> retainIDs) { Set<String> toBeRemoved = new HashSet<String>(m_imageMap.keySet()); for (String id : retainIDs) toBeRemoved.remove(id); for (String id : toBeRemoved) m_imageMap.remove(id); } public static boolean equals(ImageIcon image, String id) { String description = image.getDescription(); return (description.startsWith(IMG_ID_PREFIX) && description.substring(IMG_ID_PREFIX.length()).equals(id)); } public static boolean equals(List<ImageIcon> images, List<String> ids) { if (images.size() != ids.size()) return false; for (ImageIcon icon : images) { String id = ""; String description = icon.getDescription(); if (description.startsWith(IMG_ID_PREFIX)) { id = description.substring(IMG_ID_PREFIX.length()); if (!ids.contains(id)) return false; } else { return false; } } return true; } public List<ImageIcon> toImageIcons(List<String> ids) { List<ImageIcon> images = new LinkedList<ImageIcon>(); if (ids == null) return images; for (String id : ids) { ImageIcon image = getImage(id); if (image != null) images.add(image); } return images; } public void clear() { m_imageMap.clear(); } private ImageRepository() // singleton { } }