001 /* PAVLOV -- Multiple Choice Study System 002 * Copyright (C) 2000 - 2004 T.J. Willis 003 * 004 * This program is free software; you can redistribute it and/or 005 * modify it under the terms of the GNU General Public License 006 * as published by the Free Software Foundation; either version 2 007 * of the License, or (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRNTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program; if not, write to the Free Software 016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. 017 * 018 * $Header: /cvsroot/pavlov/net/sourceforge/pavlov/randommedia/AbstractRandomMediaFactory.java,v 1.8 2004/06/22 06:50:21 tj_willis Exp $ 019 */ 020 package net.sourceforge.pavlov.randommedia; 021 022 import java.awt.event.*; 023 import java.io.File; 024 import java.net.URL; 025 import java.util.Stack; 026 import java.util.Vector; 027 import net.sourceforge.pavlov.event.MediaRootChangedListener; 028 import net.sourceforge.pavlov.zipUtilities.*; 029 import org.apache.log4j.*; 030 031 /** 032 * This is a base class for random media factories. A random media factory is 033 * supplied with a directory tree or JAR file or mixture of the two, and 034 * randomly supplies a media object (i.e. an image, a sound) from the files. 035 * Implementations often will require caching/preloading. 036 * @author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a> 037 * @version $Revision: 1.8 $ 038 */ 039 public abstract class AbstractRandomMediaFactory 040 implements ActionListener, RandomURLProvider 041 { 042 /** 043 * The MediaDirectoryManager that will manage my directories. 044 * 045 */ 046 // was static until Nov 20 02 047 private volatile MediaDirectoryManager manager; 048 /** 049 * The root directory of my media files. 050 * 051 */ 052 // was static until Nov 20 02 053 private volatile String rootDirName = "resources/images"; 054 055 /** 056 * Objects that want to know when the media directory structure has changed. 057 * 058 */ 059 private static volatile Vector<MediaRootChangedListener> listeners; 060 061 private Category cat 062 = Category.getInstance(AbstractRandomMediaFactory.class.getName()); 063 /** 064 * Describe <code>getFileFilter</code> method here. 065 * 066 * @return a <code>ZipCapableFileFilter</code> value 067 */ 068 protected abstract ZipCapableFileFilter getFileFilter(); 069 070 /** 071 * Creates a new <code>AbstractRandomMediaFactory</code> instance. 072 * Uses the directory "resources/images" as its root directory. 073 */ 074 public AbstractRandomMediaFactory() 075 { 076 init(); 077 } 078 079 private void init() 080 { 081 manager = new MediaDirectoryManager(); 082 refresh(); 083 listeners = new Vector<MediaRootChangedListener>(); 084 } 085 086 /** 087 * Creates a new <code>AbstractRandomMediaFactory</code> instance. 088 * 089 * @param rootDir a <code>String</code> value 090 */ 091 public AbstractRandomMediaFactory(final String rootDir) 092 { 093 rootDirName = rootDir; 094 init(); 095 } 096 097 098 /** 099 * Clears any caching mechanism. 100 * 101 */ 102 public abstract void clearCache(); 103 104 /** 105 * <code>getRootDirectory</code> returns a String representation of this 106 * factory's root directory. 107 * 108 * @return a <code>String</code> value 109 */ 110 public String getRootDirectory() 111 { 112 return rootDirName; 113 } 114 115 public void setRootDirectory(final String dir){ 116 File f = new File(dir); 117 setRootDirectory(f); 118 } 119 120 /** 121 * Sets the root directory for this media factory, clears the cache 122 * as per clearCache() and refreshes its state with refresh(). 123 * 124 * @param directory a <code>File</code> value 125 */ 126 public void setRootDirectory(final File directory) 127 { 128 if(directory==null) return; 129 //if(isAJar(directory)) 130 // rootDirName = directory.toString(); 131 //else 132 rootDirName = directory.getAbsolutePath(); 133 manager = new MediaDirectoryManager(); 134 refresh(); 135 notifyListeners(); 136 } 137 138 /** 139 * Lets all the MediaRootChangedListeners know that the MediaRoot 140 * has changed. 141 * 142 */ 143 protected void notifyListeners() 144 { 145 if(listeners==null) return; 146 // FIXED: use iterator 147 for(MediaRootChangedListener who : listeners) { 148 // for(int i=0;i<listeners.size();i++) 149 //{ 150 //MediaRootChangedListener who = (MediaRootChangedListener)listeners.elementAt(i); 151 who.mediaRootChanged(); 152 } 153 } 154 155 /** 156 * Adds an object that wants to be notified when the media directory 157 * structure has changed. 158 * 159 * @param who a <code>MediaRootChangedListener</code> value 160 */ 161 public void addMediaRootChangedListener(final MediaRootChangedListener who) 162 { 163 listeners.add(who); 164 } 165 166 /** 167 * Synch the in-memory representation up with the filesystem representation. 168 * 169 */ 170 public void refresh() { 171 clearCache(); // necessary? buggy? 172 ZipCapableFileFilter filter = getFileFilter(); //new JPEGFileFilter(); 173 manager.clear(); 174 Stack<File> directoryStack = new Stack<File>(); 175 File rootDir = new File(rootDirName); 176 //cat.debug("root dir name:" + rootDir); 177 if(rootDir==null) return; 178 //assert rootDir!=null : "RootDir is null"; 179 RandomMediaDirectory root = new RandomMediaDirectory(rootDir, filter); 180 manager.addEnabled(root); 181 directoryStack.push(rootDir); 182 while (!directoryStack.empty()) { 183 File j = directoryStack.pop(); 184 Vector<File> tmp = null; 185 assert j!=null : "File is null"; 186 String ff = j.getName(); 187 //cat.debug("ff = " + ff); 188 assert ff!=null : "File is null"; 189 if(JarUtilities.isAJar(j)){ 190 RandomMediaJarFile jar = new RandomMediaJarFile(j, filter); 191 manager.addEnabled(jar); 192 tmp = jar.getSubdirectories(); 193 } else { 194 RandomMediaDirectory dir = new RandomMediaDirectory(j,filter); 195 manager.addEnabled(dir); 196 tmp = dir.getSubdirectories(); 197 } 198 if(tmp!=null) 199 directoryStack.addAll(tmp); 200 } 201 notifyListeners(); 202 } 203 204 /** 205 * This enables, i.e. allows random media to be selected from, the 206 * given directory. 207 * 208 * @param directory a <code>RandomMediaDirectory</code> value 209 */ 210 public void enableDirectory(final RandomMediaDirectory directory){ 211 manager.addEnabled(directory); 212 clearCache(); 213 notifyListeners(); 214 } 215 216 /** 217 * Enables the named RandomMediaDirectory. 218 * 219 * @param dirName a <code>String</code> value 220 */ 221 public void enableDirectory(final String dirName) { 222 assert manager!=null : "Manager is null"; 223 RandomMediaDirectory dir = manager.getDirectory(dirName); 224 assert dir!=null : "Enabling nexist dir " + dirName; 225 manager.enableDirectory(dir); 226 clearCache(); 227 notifyListeners(); 228 } 229 230 /** 231 * Disables the named RandomMediaDirectory. 232 * 233 * @param dirName a <code>String</code> value 234 */ 235 public void disableDirectory(final String dirName) { 236 assert manager!=null : "Manager is null"; 237 RandomMediaDirectory dir = manager.getDirectory(dirName); 238 assert dir!=null : "Disabling nexist dir " + dirName; 239 manager.disableDirectory(dir); 240 clearCache(); 241 notifyListeners(); 242 } 243 244 /** 245 * Removes all directories and clears any cache. 246 * 247 */ 248 public void clearDirectories() { 249 manager.clear(); 250 clearCache(); 251 notifyListeners(); 252 } 253 254 255 /** 256 * Toggles the enabled state of the named RandomMediaDirectory. 257 * 258 */ 259 public void toggleEnabled(final String dirName) { 260 //cat.debug("Toggling directory : " + dirName); 261 RandomMediaDirectory dir = manager.getDirectory(dirName); 262 assert dir!=null : "Toggling nexist dir " + dirName; 263 manager.toggleDirectory(dir); 264 clearCache(); 265 notifyListeners(); 266 } 267 268 /** 269 * Returns whether the named directory is enabled or not. 270 * 271 * @param dirName a <code>String</code> value 272 * @return a <code>boolean</code> value 273 */ 274 public boolean isDirectoryEnabled(final String dirName) { 275 return manager.isEnabled(dirName); 276 } 277 278 /** 279 * Returns a count of items in enabled directories. 280 * 281 * @return an <code>int</code> value 282 */ 283 public int getNumberOfEnabledItems() { 284 return manager.getEnabledSize(); 285 } 286 287 /** 288 * Returns a count of items in enabled and disabled directories. 289 * 290 * @return an <code>int</code> value 291 */ 292 public int getNumberOfTotalItems() { 293 return manager.getTotalSize(); 294 } 295 296 297 /** 298 * Returns a count of items in disabled directories. 299 * 300 * @return an <code>int</code> value 301 */ 302 public int getNumberOfDisabledItems() 303 { 304 return manager.getDisabledSize(); 305 } 306 307 /** 308 * Returns a random URL from one of the enabled directories. 309 * 310 * @return an <code>URL</code> value 311 */ 312 public synchronized URL getRandomURL() 313 { 314 URL crap2 = null; 315 try 316 { 317 assert manager!=null: "Manager is null"; 318 crap2 = manager.getRandomURL(); 319 //cat.debug("rand url is " + crap2); 320 } 321 catch (Exception ex) 322 { 323 cat.debug("Exception getting random url",ex); 324 return null; 325 } 326 assert crap2!=null: "Got Null URL"; 327 return crap2; 328 329 } 330 331 332 /** 333 * Returns a string array of subdirectory names. 334 * @return a <code>String[]</code> value 335 */ 336 public String[] getSubDirectoryNames() { 337 return manager.getSubDirNames(); 338 } 339 340 /** 341 * Toggles the enabled state of a RandomMediaDirectory named by the 342 * ActionEvent's ActionCommand. This is useful when you have 343 * widgets such as CheckBoxes with media directory names. 344 * @param e an <code>ActionEvent</code> value 345 */ 346 public void actionPerformed(ActionEvent e) { 347 String x = e.getActionCommand(); 348 toggleEnabled(x); 349 } 350 351 } 352 353 354 355