KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > progress > module > Controller


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20
21 package org.netbeans.progress.module;
22
23 import java.awt.Component JavaDoc;
24 import java.awt.event.ActionListener JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collection JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.logging.Level JavaDoc;
32 import java.util.logging.Logger JavaDoc;
33 import javax.swing.SwingUtilities JavaDoc;
34 import javax.swing.Timer JavaDoc;
35 import org.netbeans.progress.spi.InternalHandle;
36 import org.netbeans.progress.spi.ProgressEvent;
37 import org.netbeans.progress.spi.ProgressUIWorker;
38 import org.netbeans.progress.spi.ProgressUIWorkerProvider;
39 import org.netbeans.progress.spi.ProgressUIWorkerWithModel;
40 import org.netbeans.progress.spi.TaskModel;
41 import org.openide.util.Lookup;
42
43 /**
44  *
45  * @author Milos Kleint (mkleint@netbeans.org)
46  */

47 public /* final - because of tests */ class Controller implements Runnable JavaDoc, ActionListener JavaDoc {
48     
49     // non-private so that it can be accessed from the tests
50
public static Controller defaultInstance;
51     
52     private ProgressUIWorker component;
53     private TaskModel model;
54     private List JavaDoc<ProgressEvent> eventQueue;
55     private boolean dispatchRunning;
56     protected Timer JavaDoc timer;
57     private long timerStart = 0;
58     private static final int TIMER_QUANTUM = 400;
59     
60     /**
61      * initial delay for ading progress indication into the UI. if finishes earlier,
62      * not shown at all, applies just to the status line (default) comtroller.
63      */

64     public static final int INITIAL_DELAY = 500;
65     
66     /** Creates a new instance of Controller */
67     public Controller(ProgressUIWorker comp) {
68         component = comp;
69         model = new TaskModel();
70         eventQueue = new ArrayList JavaDoc<ProgressEvent>();
71         dispatchRunning = false;
72         timer = new Timer JavaDoc(TIMER_QUANTUM, this);
73         timer.setRepeats(false);
74     }
75
76     public static synchronized Controller getDefault() {
77         if (defaultInstance == null) {
78             ProgressUIWorkerProvider prov = Lookup.getDefault().lookup(ProgressUIWorkerProvider.class);
79             if (prov == null) {
80                 Logger.getLogger(Controller.class.getName()).log(Level.CONFIG, "Using fallback trivial progress implementation");
81                 prov = new TrivialProgressUIWorkerProvider();
82             }
83             ProgressUIWorkerWithModel component = prov.getDefaultWorker();
84             defaultInstance = new Controller(component);
85             component.setModel(defaultInstance.getModel());
86         }
87         return defaultInstance;
88     }
89     
90     // to be called on the default instance only..
91
Component JavaDoc getVisualComponent() {
92         if (component instanceof Component JavaDoc) {
93             return (Component JavaDoc)component;
94         }
95         return null;
96     }
97     
98     
99     public TaskModel getModel() {
100         return model;
101     }
102     
103     public void start(InternalHandle handle) {
104         ProgressEvent event = new ProgressEvent(handle, ProgressEvent.TYPE_START, isWatched(handle));
105         if (this == getDefault() && handle.getInitialDelay() > 100) {
106             // default controller
107
postEvent(event, true);
108         } else {
109             runImmediately(Collections.singleton(event));
110         }
111     }
112     
113     public void finish(InternalHandle handle) {
114         ProgressEvent event = new ProgressEvent(handle, ProgressEvent.TYPE_FINISH, isWatched(handle));
115         postEvent(event);
116     }
117     
118     public void toIndeterminate(InternalHandle handle) {
119         ProgressEvent event = new ProgressEvent(handle, ProgressEvent.TYPE_SWITCH, isWatched(handle));
120         postEvent(event);
121     }
122     
123     public void toSilent(InternalHandle handle, String JavaDoc message) {
124         ProgressEvent event = new ProgressEvent(handle, ProgressEvent.TYPE_SILENT, isWatched(handle), message);
125         postEvent(event);
126     }
127     
128     
129     public void toDeterminate(InternalHandle handle) {
130         ProgressEvent event = new ProgressEvent(handle, ProgressEvent.TYPE_SWITCH, isWatched(handle));
131         postEvent(event);
132     }
133     
134     public void progress(InternalHandle handle, String JavaDoc msg,
135                   int units, int percentage, long estimate) {
136         ProgressEvent event = new ProgressEvent(handle, msg, units, percentage, estimate, isWatched(handle));
137         postEvent(event);
138     }
139     
140     public ProgressEvent snapshot(InternalHandle handle, String JavaDoc msg,
141                   int units, int percentage, long estimate) {
142         if (handle.isInSleepMode()) {
143             return new ProgressEvent(handle, ProgressEvent.TYPE_SILENT, isWatched(handle), msg);
144         }
145         return new ProgressEvent(handle, msg, units, percentage, estimate, isWatched(handle));
146     }
147     
148     
149     public void explicitSelection(InternalHandle handle) {
150         InternalHandle old = model.getExplicitSelection();
151         model.explicitlySelect(handle);
152         Collection JavaDoc<ProgressEvent> evnts = new ArrayList JavaDoc<ProgressEvent>();
153         evnts.add(handle.requestStateSnapshot());
154         if (old != null && old != handle) {
155             // refresh the old one, results in un-bodling the text.
156
evnts.add(old.requestStateSnapshot());
157         }
158         runImmediately(evnts);
159     }
160     
161     public void displayNameChange(InternalHandle handle, int units, int percentage, long estimate, String JavaDoc display) {
162         Collection JavaDoc<ProgressEvent> evnts = new ArrayList JavaDoc<ProgressEvent>();
163         evnts.add(new ProgressEvent(handle, null, units, percentage, estimate, isWatched(handle), display));
164         runImmediately(evnts);
165     }
166     
167     private boolean isWatched(InternalHandle hndl) {
168         return model.getExplicitSelection() == hndl;
169     }
170     
171     /**
172      *
173      */

174     void runImmediately(Collection JavaDoc<ProgressEvent> events) {
175         synchronized (this) {
176             // need to add to queue immediately in the current thread
177
eventQueue.addAll(events);
178             dispatchRunning = true;
179         }
180         // trigger ui update as fast as possible.
181
if (SwingUtilities.isEventDispatchThread()) {
182            run();
183         } else {
184            SwingUtilities.invokeLater(this);
185         }
186         
187     }
188     
189     void postEvent(final ProgressEvent event) {
190         postEvent(event, false);
191     }
192     
193     void postEvent(final ProgressEvent event, boolean shortenPeriod) {
194         synchronized (this) {
195             eventQueue.add(event);
196             if (!dispatchRunning) {
197                 timerStart = System.currentTimeMillis();
198                 int delay = timer.getInitialDelay();
199                 // period of timer is longer than required by the handle -> shorten it.
200
if (shortenPeriod && timer.getInitialDelay() > event.getSource().getInitialDelay()) {
201                     delay = event.getSource().getInitialDelay();
202                 }
203                 dispatchRunning = true;
204                 resetTimer(delay, true);
205             } else if (shortenPeriod) {
206                 // time remaining is longer than required by the handle's initial delay.
207
// restart with shorter time.
208
if (System.currentTimeMillis() - timerStart > event.getSource().getInitialDelay()) {
209                     resetTimer(event.getSource().getInitialDelay(), true);
210                 }
211             }
212         }
213     }
214     
215     protected void resetTimer(int initialDelay, boolean restart) {
216         timer.setInitialDelay(initialDelay);
217         if (restart) {
218             timer.restart();
219         }
220     }
221      
222     
223     /**
224      * can be run from awt only.
225      */

226     public void run() {
227         HashMap JavaDoc<InternalHandle, ProgressEvent> map = new HashMap JavaDoc<InternalHandle, ProgressEvent>();
228         boolean hasShortOne = false;
229         long minDiff = TIMER_QUANTUM;
230         
231         InternalHandle oldSelected = model.getSelectedHandle();
232         long stamp = System.currentTimeMillis();
233         synchronized (this) {
234             Iterator JavaDoc<ProgressEvent> it = eventQueue.iterator();
235             Collection JavaDoc<InternalHandle> justStarted = new ArrayList JavaDoc<InternalHandle>();
236             while (it.hasNext()) {
237                 ProgressEvent event = it.next();
238                 boolean isShort = (stamp - event.getSource().getTimeStampStarted()) < event.getSource().getInitialDelay();
239                 if (event.getType() == ProgressEvent.TYPE_START) {
240                     if (event.getSource().isCustomPlaced() || !isShort) {
241                         model.addHandle(event.getSource());
242                     } else {
243                         justStarted.add(event.getSource());
244                     }
245                 }
246                 else if (event.getType() == ProgressEvent.TYPE_FINISH &&
247                        (! justStarted.contains(event.getSource())))
248                 {
249                     model.removeHandle(event.getSource());
250                 }
251                 ProgressEvent lastEvent = (ProgressEvent)map.get(event.getSource());
252                 if (lastEvent != null && event.getType() == ProgressEvent.TYPE_FINISH &&
253                         justStarted.contains(event.getSource()) && isShort)
254                 {
255                     // if task quits really fast, ignore..
256
// defined 'really fast' as being shorter than initial delay
257
map.remove(event.getSource());
258                     justStarted.remove(event.getSource());
259                 } else {
260                     if (lastEvent != null) {
261                         // preserve last message
262
event.copyMessageFromEarlier(lastEvent);
263                         // preserve the switched state
264
if (lastEvent.isSwitched()) {
265                             event.markAsSwitched();
266                         }
267                     }
268                     map.put(event.getSource(), event);
269                 }
270                 it.remove();
271             }
272             // now re-add the just started events into queue
273
// if they don't last longer than the initial delay of the task.
274
// applies just for status bar items
275
Iterator JavaDoc<InternalHandle> startIt = justStarted.iterator();
276             while (startIt.hasNext()) {
277                 InternalHandle hndl = startIt.next();
278                 long diff = stamp - hndl.getTimeStampStarted();
279                 if (diff >= hndl.getInitialDelay()) {
280                     model.addHandle(hndl);
281                 } else {
282                     eventQueue.add(new ProgressEvent(hndl, ProgressEvent.TYPE_START, isWatched(hndl)));
283                     ProgressEvent evnt = (ProgressEvent)map.remove(hndl);
284                     if (evnt.getType() != ProgressEvent.TYPE_START) {
285                         eventQueue.add(evnt);
286                     }
287                     hasShortOne = true;
288                     minDiff = Math.min(minDiff, hndl.getInitialDelay() - diff);
289                 }
290             }
291         }
292         InternalHandle selected = model.getSelectedHandle();
293         selected = selected == null ? oldSelected : selected;
294         Iterator JavaDoc<ProgressEvent> it = map.values().iterator();
295         while (it.hasNext()) {
296             ProgressEvent event = it.next();
297             if (selected == event.getSource()) {
298                 component.processSelectedProgressEvent(event);
299             }
300             component.processProgressEvent(event);
301         }
302         synchronized (this) {
303             timer.stop();
304             if (hasShortOne) {
305                 timerStart = System.currentTimeMillis();
306                 resetTimer((int)Math.max(100, minDiff), true);
307             } else {
308                 dispatchRunning = false;
309                 resetTimer(TIMER_QUANTUM, false);
310             }
311         }
312     }
313
314     /**
315      * used by Timer
316      */

317     public void actionPerformed(java.awt.event.ActionEvent JavaDoc actionEvent) {
318         run();
319     }
320
321     
322
323 }
324
Popular Tags