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