View Javadoc

1   /*
2    *   Magic-Project is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  package net.sf.magicproject.management;
20  
21  import java.awt.Color;
22  import java.awt.Graphics;
23  import java.awt.Image;
24  import java.net.URL;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Set;
28  
29  import net.sf.magicproject.database.DatabaseFactory;
30  import net.sf.magicproject.tools.Log;
31  import net.sf.magicproject.tools.Picture;
32  import net.sf.magicproject.ui.MagicUIComponents;
33  
34  /***
35   * A monitored content represents partial data representation : source,
36   * destination, content length to proceed, content proceeded length.
37   * 
38   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
39   * @since 0.91
40   */
41  public class MonitoredCheckContent implements Runnable {
42  
43  	/***
44  	 * The total content length to load.
45  	 */
46  	private int contentLength;
47  
48  	/***
49  	 * The current content length to load.
50  	 */
51  	private int currentLength;
52  
53  	/***
54  	 * Notficaytion period.
55  	 */
56  	public static final int NOTIFICATION_PERIOD = 300;
57  
58  	/***
59  	 * Is the content is completely loaded.
60  	 */
61  	private boolean isFinished = false;
62  
63  	/***
64  	 * The listener
65  	 */
66  	protected Set<MonitorListener> listeners;
67  
68  	/***
69  	 * Notification counter
70  	 */
71  	protected int notificationCounter = 0;
72  
73  	/***
74  	 * The list of remotes files.
75  	 */
76  	protected List<String> remoteFiles;
77  
78  	/***
79  	 * The destination (local) files.
80  	 */
81  	protected List<String> localFiles;
82  
83  	/***
84  	 * The string delimiting the jar/zip content.
85  	 */
86  	public static final String STR_ZIP_PATH = "!/";
87  
88  	/***
89  	 * The wrapped content.
90  	 */
91  	private Image image;
92  
93  	/***
94  	 * Return the current content.
95  	 * 
96  	 * @return the current content.
97  	 */
98  	public Image getContent() {
99  		return image;
100 	}
101 
102 	/***
103 	 * Create a new instance of this class.
104 	 * 
105 	 * @param content
106 	 *          the completed content.
107 	 */
108 	public MonitoredCheckContent(Image content) {
109 		this.image = content;
110 		this.isFinished = true;
111 	}
112 
113 	/***
114 	 * Create a new instance of this class.
115 	 * 
116 	 * @param localFiles
117 	 *          the destination (local) files.
118 	 * @param remoteFiles
119 	 *          the list of remotes files.
120 	 * @param listener
121 	 *          the listener to notify.
122 	 */
123 	public MonitoredCheckContent(List<String> localFiles,
124 			List<String> remoteFiles, MonitorListener listener) {
125 		this.localFiles = localFiles;
126 		this.remoteFiles = remoteFiles;
127 		if (listener != null) {
128 			this.listeners = new HashSet<MonitorListener>();
129 			this.listeners.add(listener);
130 		}
131 		this.image = DatabaseFactory.blankImage;
132 	}
133 
134 	/***
135 	 * Is the whole content is got.
136 	 * 
137 	 * @return true if the whole content is got.
138 	 */
139 	public boolean isFinished() {
140 		return isFinished;
141 	}
142 
143 	/***
144 	 * Inidicates this content is completely loaded.
145 	 */
146 	public void setFinished() {
147 		this.isFinished = true;
148 		if (listeners != null) {
149 			synchronized (listeners) {
150 				for (MonitorListener listener : listeners) {
151 					listener.notifyChange();
152 				}
153 			}
154 			// now we wait the acknowledge from the listeners
155 			try {
156 				while (true) {
157 					Thread.sleep(NOTIFICATION_PERIOD);
158 					synchronized (listeners) {
159 						if (listeners.isEmpty())
160 							break;
161 					}
162 				}
163 			} catch (InterruptedException e) {
164 				// Ignore this error and terminate this thread
165 			}
166 			listeners = null;
167 		}
168 
169 	}
170 
171 	/***
172 	 * Add a listener.
173 	 * 
174 	 * @param listener
175 	 *          the listener to add.
176 	 */
177 	public final void addListener(MonitorListener listener) {
178 		if (listeners != null) {
179 			synchronized (listeners) {
180 				listeners.add(listener);
181 			}
182 		}
183 		if (isFinished()) {
184 			listener.notifyChange();
185 		}
186 	}
187 
188 	/***
189 	 * Paint the progress bar of the content download on the given graphics.
190 	 * 
191 	 * @param g
192 	 *          the used graphics to draw our progressbar.
193 	 */
194 	public void paintNotification(Graphics g) {
195 		g.drawImage(MagicUIComponents.targetTimer.byGifPictures[notificationCounter
196 				% MagicUIComponents.targetTimer.byGifPictures.length], 15, 15, null);
197 		g.setColor(Color.WHITE);
198 		if (contentLength <= 0) {
199 			g.drawString("? %", 15, 45);
200 		} else {
201 			g.drawString(String.valueOf(currentLength * 100 / contentLength) + "%",
202 					15, 45);
203 		}
204 	}
205 
206 	/***
207 	 * Unregister the specified lister from the monitored content listeners.
208 	 * 
209 	 * @param listener
210 	 *          the listener acknowledging the finished content.
211 	 */
212 	public void acknowledgeFinished(MonitorListener listener) {
213 		if (listeners != null && !listeners.isEmpty()) {
214 			synchronized (listeners) {
215 				listeners.remove(listener);
216 			}
217 		}
218 	}
219 
220 	/***
221 	 * Start the download.
222 	 */
223 	public void start() {
224 		new Thread(this).start();
225 	}
226 
227 	public void run() {
228 		for (String localFile : localFiles) {
229 			try {
230 				if (localFile != null) {
231 					MonitoredCheckContent tmpContent = Picture.loadImage(localFile, null,
232 							this);
233 					if (tmpContent != null && tmpContent.getContent() != null) {
234 						image = tmpContent.getContent();
235 						setFinished();
236 						return;
237 					}
238 				}
239 			} catch (Exception e1) {
240 				// Nothing to, it was just a test.
241 			}
242 		}
243 		for (int i = 0; i < remoteFiles.size(); i++) {
244 			String localFile = localFiles.get(i);
245 			String remoteFile = remoteFiles.get(i);
246 			try {
247 				if (localFile != null && remoteFile != null) {
248 					MonitoredCheckContent tmpContent = Picture.loadImage(localFile,
249 							new URL(remoteFile), this);
250 					if (tmpContent != null && tmpContent.getContent() != null) {
251 						image = tmpContent.getContent();
252 						setFinished();
253 						return;
254 					}
255 				}
256 			} catch (Exception e1) {
257 				// Ignore this error, and test the next pair
258 				Log.info(e1.getMessage());
259 			}
260 		}
261 	}
262 
263 	/***
264 	 * Update the content data progress.
265 	 * 
266 	 * @param contentLength
267 	 *          the total content length to load.
268 	 * @param currentLength
269 	 *          the current content length to load.
270 	 */
271 	public void updateProgress(int contentLength, int currentLength) {
272 		this.contentLength = contentLength;
273 		this.currentLength = currentLength;
274 		this.notificationCounter++;
275 		if (listeners != null) {
276 			synchronized (listeners) {
277 				for (MonitorListener listener : listeners) {
278 					listener.notifyChange();
279 				}
280 			}
281 		}
282 	}
283 }