001/* 002 * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games. 003 * Copyright (C) 2000-2011 The Gridarta Developers. 004 * 005 * This program is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU General Public License as published by 007 * the Free Software Foundation; either version 2 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License along 016 * with this program; if not, write to the Free Software Foundation, Inc., 017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 018 */ 019 020package net.sf.gridarta.gui.map; 021 022import java.awt.BorderLayout; 023import java.awt.Dimension; 024import java.awt.Image; 025import java.beans.PropertyChangeEvent; 026import java.beans.PropertyChangeListener; 027import java.io.File; 028import java.util.prefs.Preferences; 029import javax.swing.Action; 030import javax.swing.Icon; 031import javax.swing.ImageIcon; 032import javax.swing.JButton; 033import javax.swing.JComponent; 034import javax.swing.JFileChooser; 035import javax.swing.JLabel; 036import javax.swing.JScrollPane; 037import javax.swing.SwingConstants; 038import javax.swing.filechooser.FileView; 039import net.sf.gridarta.MainControl; 040import net.sf.gridarta.gui.mapimagecache.MapImageCache; 041import net.sf.japi.swing.action.ActionBuilder; 042import net.sf.japi.swing.action.ActionBuilderFactory; 043import net.sf.japi.swing.action.ActionMethod; 044import net.sf.japi.swing.action.ToggleAction; 045import org.jetbrains.annotations.NotNull; 046import org.jetbrains.annotations.Nullable; 047 048/** 049 * Abstract base class for MapPreviewAccessories which are used for previewing 050 * maps in JFileChoosers. 051 * @author <a href="mailto:cher@riedquat.de">Christian Hujer</a> 052 */ 053public class MapPreviewAccessory extends JComponent { 054 055 /** 056 * The serial version UID. 057 */ 058 private static final long serialVersionUID = 1L; 059 060 /** 061 * Action Builder. 062 */ 063 @NotNull 064 private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta"); 065 066 /** 067 * Preferences. 068 */ 069 @NotNull 070 private static final Preferences preferences = Preferences.userNodeForPackage(MainControl.class); 071 072 /** 073 * Preferences key for automatic preview generation. 074 */ 075 @NotNull 076 private static final String PREFERENCES_AUTO_GENERATE_PREVIEW = "autoGeneratePreviews"; 077 078 /** 079 * The cache for map images. 080 */ 081 @NotNull 082 private final MapImageCache<?, ?, ?> mapImageCache; 083 084 /** 085 * The preview label. 086 */ 087 @NotNull 088 private final JLabel preview = new JLabel(); 089 090 /** 091 * ToggleAction for auto-generate preview. 092 */ 093 @NotNull 094 private final ToggleAction autoGeneratePreview = (ToggleAction) ACTION_BUILDER.createToggle(false, "autoGeneratePreviews", this); 095 096 /** 097 * Action for generating preview. 098 */ 099 private final Action genPreview = ACTION_BUILDER.createAction(false, "genPreview", this); 100 101 /** 102 * The file chooser instance. 103 */ 104 @NotNull 105 private final JFileChooser fileChooser; 106 107 /** 108 * The currently selected files, or <code>null</code> if no file is 109 * selected. 110 */ 111 @Nullable 112 private File[] selectedFiles; 113 114 /** 115 * Whether previews should be auto-generated. 116 */ 117 private boolean autoGeneratePreviews; 118 119 /** 120 * Creates an MapPreviewAccessory. 121 * @param mapImageCache the map image cache to use 122 * @param fileChooser the file chooser to attach to 123 */ 124 public MapPreviewAccessory(@NotNull final MapImageCache<?, ?, ?> mapImageCache, @NotNull final JFileChooser fileChooser) { 125 this.mapImageCache = mapImageCache; 126 this.fileChooser = fileChooser; 127 buildUI(); 128 setPreview("No Preview available"); 129 130 final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { 131 132 @Override 133 public void propertyChange(final PropertyChangeEvent evt) { 134 final String prop = evt.getPropertyName(); 135 if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) { 136 setPreview("No Preview available"); 137 } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) { 138 final File selectedFile = (File) evt.getNewValue(); 139 if (selectedFile != null) { 140 final Image previewImage = getMapPreview(selectedFile); 141 if (previewImage != null) { 142 setPreview(previewImage); 143 } else { 144 setPreview("No Preview available"); 145 } 146 } else { 147 setPreview("No Preview available"); 148 } 149 } else if (JFileChooser.SELECTED_FILES_CHANGED_PROPERTY.equals(prop)) { 150 selectedFiles = (File[]) evt.getNewValue(); 151 } 152 } 153 154 }; 155 fileChooser.addPropertyChangeListener(propertyChangeListener); 156 fileChooser.setFileView(new MapFileView()); 157 } 158 159 /** 160 * Build the user interface. 161 */ 162 private void buildUI() { 163 setAutoGeneratePreviews(preferences.getBoolean(PREFERENCES_AUTO_GENERATE_PREVIEW, false)); 164 setPreferredSize(new Dimension(240, 115)); 165 setLayout(new BorderLayout()); 166 add(autoGeneratePreview.createCheckBox(), BorderLayout.NORTH); 167 add(new JButton(genPreview), BorderLayout.SOUTH); 168 preview.setHorizontalAlignment(SwingConstants.CENTER); 169 add(new JScrollPane(preview), BorderLayout.CENTER); 170 } 171 172 /** 173 * Updates the text and icon of {@link #preview}. 174 * @param image the icon to set or <code>null</code> 175 */ 176 @SuppressWarnings("NullableProblems") 177 private void setPreview(@Nullable final Image image) { 178 preview.setIcon(image == null ? null : new ImageIcon(image)); 179 preview.setText(null); 180 } 181 182 /** 183 * Updates the text and icon of {@link #preview}. 184 * @param text the text to set 185 */ 186 private void setPreview(@NotNull final String text) { 187 preview.setIcon(null); 188 preview.setText(text); 189 } 190 191 /** 192 * Switch automatic preview generation. 193 * @param autoGeneratePreviews <code>true</code> for automatically 194 * generating previews, <code>false</code> otherwise 195 */ 196 @ActionMethod 197 public void setAutoGeneratePreviews(final boolean autoGeneratePreviews) { 198 this.autoGeneratePreviews = autoGeneratePreviews; 199 autoGeneratePreview.setSelected(autoGeneratePreviews); 200 preferences.putBoolean(PREFERENCES_AUTO_GENERATE_PREVIEW, autoGeneratePreviews); 201 if (autoGeneratePreviews) { 202 fileChooser.validate(); 203 fileChooser.repaint(); 204 } 205 } 206 207 /** 208 * Get whether to automatically generate previews. 209 * @return <code>true</code> if previews are automatically generated, 210 * otherwise <code>false</code> 211 */ 212 @ActionMethod 213 public boolean isAutoGeneratePreviews() { 214 return autoGeneratePreviews; 215 } 216 217 /** 218 * Generate a preview. 219 */ 220 @ActionMethod 221 public void genPreview() { 222 final File[] files = selectedFiles; 223 if (files == null || files.length == 0) { 224 return; 225 } 226 227 for (final File file : files) { 228 mapImageCache.flush(file); 229 230 final Image image = mapImageCache.getOrCreatePreview(file); 231 setPreview(image); 232 } 233 fileChooser.validate(); 234 fileChooser.repaint(); 235 } 236 237 /** 238 * Get an icon. 239 * @param mapFile map file to get icon for 240 * @return icon for file mapFile or <code>null</code> if the icon was 241 * neither cached nor loadable 242 */ 243 @Nullable 244 public Image getMapIcon(@NotNull final File mapFile) { 245 return autoGeneratePreview.isSelected() ? mapImageCache.getOrCreateIcon(mapFile) : mapImageCache.getIcon(mapFile); 246 } 247 248 /** 249 * Get a preview. 250 * @param mapFile map file to get preview for 251 * @return preview for file mapFile or <code>null</code> if the preview was 252 * neither cached nor loadable 253 */ 254 @Nullable 255 private Image getMapPreview(@NotNull final File mapFile) { 256 return autoGeneratePreview.isSelected() ? mapImageCache.getOrCreatePreview(mapFile) : mapImageCache.getPreview(mapFile); 257 } 258 259 /** 260 * FileView for giving icons to map files. 261 */ 262 private class MapFileView extends FileView { 263 264 @Override 265 public Icon getIcon(@NotNull final File f) { 266 @Nullable final Image image; 267 if (fileChooser.getCurrentDirectory().equals(f.getParentFile())) { 268 image = getMapIcon(f); 269 } else { 270 image = null; 271 } 272 return image != null ? new ImageIcon(image) : super.getIcon(f); 273 } 274 275 } 276 277}