001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: //(the "License"); you may not use this file except in compliance with the
004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: //Software distributed under the License is distributed on an "AS IS" basis,
007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: //for the specific language governing rights and
009: //limitations under the License.
010: //
011: //The Original Code is "The Columba Project"
012: //
013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: //All Rights Reserved.
018:
019: package org.columba.core.command;
020:
021: import java.util.List;
022: import java.util.Vector;
023: import java.util.logging.Logger;
024:
025: import javax.swing.event.EventListenerList;
026:
027: import org.columba.api.command.IWorkerStatusChangeListener;
028: import org.columba.api.command.IWorkerStatusController;
029: import org.columba.api.command.WorkerStatusChangedEvent;
030: import org.columba.api.exception.IExceptionListener;
031: import org.columba.core.base.SwingWorker;
032:
033: /**
034: * Worker additionally sends status information updates to the
035: * {@link TaskManager}.
036: * <p>
037: * This updates get displayed in the StatusBar.
038: * <p>
039: * Note that {@link Command}objects get {@link Worker}objects only when
040: * executed.
041: *
042: * @author fdietz
043: */
044: public class Worker extends SwingWorker implements
045: IWorkerStatusController {
046:
047: private static final Logger LOG = Logger
048: .getLogger("org.columba.core.command"); //$NON-NLS-1$
049:
050: /**
051: * Constant definining the delay used when using
052: * clearDisplayTextWithDelay(). Defined to be 500 millisec.
053: */
054: private static final int CLEAR_DELAY = 500;
055:
056: protected Command op;
057:
058: protected int operationMode;
059:
060: protected CommandProcessor boss;
061:
062: protected String displayText;
063:
064: protected int progressBarMax;
065:
066: protected int progressBarValue;
067:
068: protected boolean cancelled;
069:
070: protected List<IWorkerStatusChangeListener> workerStatusChangeListeners;
071:
072: private int timeStamp;
073:
074: protected EventListenerList listenerList = new EventListenerList();
075:
076: public Worker(CommandProcessor parent) {
077: super ();
078:
079: this .boss = parent;
080:
081: displayText = ""; //$NON-NLS-1$
082: progressBarValue = 0;
083: progressBarMax = 0;
084:
085: cancelled = false;
086:
087: workerStatusChangeListeners = new Vector<IWorkerStatusChangeListener>();
088: }
089:
090: public void process(Command theCommand, int theOperationMode,
091: int theTimeStamp) {
092: this .op = theCommand;
093: this .operationMode = theOperationMode;
094: this .timeStamp = theTimeStamp;
095: }
096:
097: public int getPriority() {
098: return op.getPriority();
099: }
100:
101: private void returnLocks(int opMode) {
102: op.releaseAllFolderLocks();
103: }
104:
105: /**
106: * Method runs in background. Every Command.execute method is wrapped
107: * here.
108: * <p>
109: * All general exceptions are caught here, nice error dialogs shown to
110: * the users.
111: *
112: * @see org.columba.core.base.SwingWorker#construct()
113: */
114: @Override
115: public Object construct() {
116:
117: try {
118: op.process(this );
119:
120: } catch (CommandCancelledException e) {
121: LOG.info("Command cancelled: " + this ); //$NON-NLS-1$
122: } catch (Exception e) {
123:
124: // exception handler should handle all error handling stuff
125: fireExceptionOccured(e);
126: }
127:
128: returnLocks(operationMode);
129:
130: return null;
131: }
132:
133: @Override
134: public void finished() {
135: try {
136: op.finish();
137: } catch (Exception e) {
138: // Must create a ExceptionProcessor
139: e.printStackTrace();
140: }
141:
142: unregister();
143: boss.operationFinished(op, this );
144: }
145:
146: private void unregister() {
147: TaskManager.getInstance().unregister(threadVar);
148:
149: WorkerStatusChangedEvent e = new WorkerStatusChangedEvent(this ,
150: getTimeStamp());
151: e.setType(WorkerStatusChangedEvent.FINISHED);
152: fireWorkerStatusChanged(e);
153: workerStatusChangeListeners.clear();
154: displayText = ""; //$NON-NLS-1$
155: progressBarValue = 0;
156: progressBarMax = 0;
157: }
158:
159: /**
160: * Sets the maximum value for the progress bar.
161: *
162: * @param max
163: * New max. value for progress bar
164: */
165: public void setProgressBarMaximum(int max) {
166: WorkerStatusChangedEvent e = new WorkerStatusChangedEvent(this ,
167: getTimeStamp());
168: e.setType(WorkerStatusChangedEvent.PROGRESSBAR_MAX_CHANGED);
169: e.setOldValue(new Integer(progressBarMax));
170:
171: progressBarMax = max;
172:
173: e.setNewValue(new Integer(progressBarMax));
174: fireWorkerStatusChanged(e);
175: }
176:
177: /**
178: * Sets the current value of the progress bar.
179: *
180: * @param aValue
181: * New current value of progress bar
182: */
183: public void setProgressBarValue(int aValue) {
184: WorkerStatusChangedEvent e = new WorkerStatusChangedEvent(this ,
185: getTimeStamp());
186: e.setType(WorkerStatusChangedEvent.PROGRESSBAR_VALUE_CHANGED);
187: e.setOldValue(new Integer(progressBarValue));
188:
189: progressBarValue = aValue;
190:
191: e.setNewValue(new Integer(progressBarValue));
192: fireWorkerStatusChanged(e);
193: }
194:
195: /**
196: * Sets the progress bar value to zero, i.e. clears the progress bar.
197: * This is the same as calling setProgressBarValue(0)
198: */
199: public void resetProgressBar() {
200: setProgressBarValue(0);
201: }
202:
203: /**
204: * Returns the max. value for the progress bar
205: */
206: public int getProgessBarMaximum() {
207: return progressBarMax;
208: }
209:
210: /**
211: * Returns the current value for the progress bar
212: */
213: public int getProgressBarValue() {
214: return progressBarValue;
215: }
216:
217: /**
218: * Returns the text currently displayed in the status bar
219: */
220: public String getDisplayText() {
221: return displayText;
222: }
223:
224: /**
225: * Set the text to be displayed in the status bar
226: *
227: * @param text
228: * Text to display in status bar
229: */
230: public void setDisplayText(String text) {
231: WorkerStatusChangedEvent e = new WorkerStatusChangedEvent(this ,
232: getTimeStamp());
233: e.setType(WorkerStatusChangedEvent.DISPLAY_TEXT_CHANGED);
234: e.setOldValue(displayText);
235:
236: displayText = text;
237:
238: e.setNewValue(displayText);
239: fireWorkerStatusChanged(e);
240: }
241:
242: /**
243: * Clears the text displayed in the status bar - without any delay
244: */
245: public void clearDisplayText() {
246: clearDisplayText(0);
247: }
248:
249: /**
250: * Clears the text displayed in the status bar - with a given delay. The
251: * delay used is 500 ms. <br>
252: * If a new text is set within this delay, the text is not cleared.
253: */
254: public void clearDisplayTextWithDelay() {
255: clearDisplayText(CLEAR_DELAY);
256: }
257:
258: /**
259: * Clears the text displayed in the status bar - with a given delay. If
260: * a new text is set within this delay, the text is not cleared.
261: *
262: * @param delay
263: * Delay in milliseconds before clearing the text
264: */
265: private void clearDisplayText(int delay) {
266: // init event
267: WorkerStatusChangedEvent e = new WorkerStatusChangedEvent(this ,
268: getTimeStamp());
269: e.setType(WorkerStatusChangedEvent.DISPLAY_TEXT_CLEARED);
270:
271: // "new value" is used to pass on the delay
272: e.setNewValue(new Integer(delay));
273:
274: // set display text stored here to an empty string (~ cleared)
275: displayText = ""; //$NON-NLS-1$
276:
277: // fire event
278: fireWorkerStatusChanged(e);
279: }
280:
281: public void addWorkerStatusChangeListener(
282: IWorkerStatusChangeListener l) {
283: workerStatusChangeListeners.add(l);
284: }
285:
286: public void removeWorkerStatusChangeListener(
287: IWorkerStatusChangeListener l) {
288: workerStatusChangeListeners.remove(l);
289: }
290:
291: protected void fireWorkerStatusChanged(WorkerStatusChangedEvent e) {
292: // if we use the commented statement, the exceptio
293: // java.util.ConcurrentModificationException
294: // is thrown ... is the worker not thread save?
295: // for (Iterator it = workerStatusChangeListeners.iterator();
296: // it.hasNext();) {
297: // ((WorkerStatusChangeListener) it.next()).workerStatusChanged(e);
298: for (int i = 0; i < workerStatusChangeListeners.size(); i++) {
299: workerStatusChangeListeners.get(i).workerStatusChanged(e);
300: }
301: }
302:
303: public void cancel() {
304: cancelled = true;
305: }
306:
307: public boolean cancelled() {
308: return cancelled;
309: }
310:
311: /**
312: * Returns the timeStamp.
313: *
314: * @return int
315: */
316: public int getTimeStamp() {
317: return timeStamp;
318: }
319:
320: /**
321: * Adds a listener.
322: */
323: public void addExceptionListener(IExceptionListener l) {
324: listenerList.add(IExceptionListener.class, l);
325: }
326:
327: /**
328: * Removes a previously registered listener.
329: */
330: public void removeExceptionListener(IExceptionListener l) {
331: listenerList.remove(IExceptionListener.class, l);
332: }
333:
334: /**
335: * Notify all listeners of the exception.
336: *
337: * @param e
338: * exception
339: */
340: private void fireExceptionOccured(Exception e) {
341: // Guaranteed to return a non-null array
342: Object[] listeners = listenerList.getListenerList();
343:
344: // Process the listeners last to first, notifying
345: // those that are interested in this event
346: for (int i = listeners.length - 2; i >= 0; i -= 2) {
347: if (listeners[i] == IExceptionListener.class) {
348: ((IExceptionListener) listeners[i + 1])
349: .exceptionOccured(e);
350: }
351: }
352: }
353:
354: /**
355: * @see org.columba.core.base.SwingWorker#start()
356: */
357: @Override
358: public Thread start() {
359: TaskManager.getInstance().register(this);
360:
361: return super.start();
362: }
363: }
|