KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > UpdateManager


1 /*
2
3    Copyright 2001-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.bridge;
19
20 import java.awt.Shape JavaDoc;
21 import java.awt.geom.AffineTransform JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.LinkedList JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.apache.batik.gvt.GraphicsNode;
30 import org.apache.batik.gvt.RootGraphicsNode;
31 import org.apache.batik.gvt.UpdateTracker;
32 import org.apache.batik.gvt.renderer.ImageRenderer;
33 import org.apache.batik.util.EventDispatcher;
34 import org.apache.batik.util.EventDispatcher.Dispatcher;
35 import org.apache.batik.util.RunnableQueue;
36 import org.w3c.dom.Document JavaDoc;
37 import org.w3c.dom.events.DocumentEvent JavaDoc;
38 import org.w3c.dom.events.Event JavaDoc;
39 import org.w3c.dom.events.EventTarget JavaDoc;
40
41 /**
42  * This class provides features to manage the update of an SVG document.
43  *
44  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
45  * @version $Id: UpdateManager.java,v 1.38 2005/03/27 08:58:30 cam Exp $
46  */

47 public class UpdateManager {
48
49     static final long MIN_REPAINT_TIME;
50     static {
51         long value = 20;
52         try {
53             String JavaDoc s = System.getProperty
54             ("org.apache.batik.min_repaint_time", "20");
55             value = Long.parseLong(s);
56         } catch (SecurityException JavaDoc se) {
57         } catch (NumberFormatException JavaDoc nfe){
58         } finally {
59             MIN_REPAINT_TIME = value;
60         }
61     }
62
63     /**
64      * The bridge context.
65      */

66     protected BridgeContext bridgeContext;
67     
68     /**
69      * The document to manage.
70      */

71     protected Document JavaDoc document;
72
73     /**
74      * The update RunnableQueue.
75      */

76     protected RunnableQueue updateRunnableQueue;
77
78     /**
79      * The RunHandler for the RunnableQueue.
80      */

81     protected RunnableQueue.RunHandler runHandler;
82
83     /**
84      * Whether the update manager is running.
85      */

86     protected boolean running;
87
88     /**
89      * Whether the suspend() method was called.
90      */

91     protected boolean suspendCalled;
92
93     /**
94      * The listeners.
95      */

96     protected List JavaDoc listeners = Collections.synchronizedList(new LinkedList JavaDoc());
97
98     /**
99      * The scripting environment.
100      */

101     protected ScriptingEnvironment scriptingEnvironment;
102
103     /**
104      * The repaint manager.
105      */

106     protected RepaintManager repaintManager;
107
108     /**
109      * The update tracker.
110      */

111     protected UpdateTracker updateTracker;
112
113     /**
114      * The GraphicsNode whose updates are to be tracked.
115      */

116     protected GraphicsNode graphicsNode;
117
118     /**
119      * Whether the manager was started.
120      */

121     protected boolean started;
122
123     /**
124      * Creates a new update manager.
125      * @param ctx The bridge context.
126      * @param gn GraphicsNode whose updates are to be tracked.
127      * @param doc The document to manage.
128      */

129     public UpdateManager(BridgeContext ctx,
130                          GraphicsNode gn,
131                          Document JavaDoc doc) {
132         bridgeContext = ctx;
133         bridgeContext.setUpdateManager(this);
134
135         document = doc;
136
137         updateRunnableQueue = RunnableQueue.createRunnableQueue();
138         runHandler = createRunHandler();
139         updateRunnableQueue.setRunHandler(runHandler);
140
141         graphicsNode = gn;
142
143         scriptingEnvironment = new ScriptingEnvironment(ctx);
144     }
145
146     /**
147      * Dispatches an 'SVGLoad' event to the document.
148      */

149     public synchronized void dispatchSVGLoadEvent()
150         throws InterruptedException JavaDoc {
151         scriptingEnvironment.loadScripts();
152         scriptingEnvironment.dispatchSVGLoadEvent();
153     }
154
155     /**
156      * Dispatches an "SVGZoom" event to the document.
157      */

158     public void dispatchSVGZoomEvent()
159         throws InterruptedException JavaDoc {
160         scriptingEnvironment.dispatchSVGZoomEvent();
161     }
162
163     /**
164      * Dispatches an "SVGZoom" event to the document.
165      */

166     public void dispatchSVGScrollEvent()
167         throws InterruptedException JavaDoc {
168         scriptingEnvironment.dispatchSVGScrollEvent();
169     }
170
171     /**
172      * Dispatches an "SVGZoom" event to the document.
173      */

174     public void dispatchSVGResizeEvent()
175         throws InterruptedException JavaDoc {
176         scriptingEnvironment.dispatchSVGResizeEvent();
177     }
178
179     /**
180      * Finishes the UpdateManager initialization.
181      */

182     public void manageUpdates(final ImageRenderer r) {
183         updateRunnableQueue.preemptLater(new Runnable JavaDoc() {
184                 public void run() {
185                     synchronized (UpdateManager.this) {
186                         running = true;
187         
188                         updateTracker = new UpdateTracker();
189                         RootGraphicsNode root = graphicsNode.getRoot();
190                         if (root != null){
191                             root.addTreeGraphicsNodeChangeListener
192                                 (updateTracker);
193                         }
194
195                         repaintManager = new RepaintManager(r);
196
197                         // Send the UpdateManagerStarted event.
198
UpdateManagerEvent ev = new UpdateManagerEvent
199                             (UpdateManager.this, null, null);
200                         fireEvent(startedDispatcher, ev);
201                         started = true;
202                     }
203                 }
204             });
205         resume();
206     }
207
208
209     /**
210      * Returns the bridge context.
211      */

212     public BridgeContext getBridgeContext() {
213         return bridgeContext;
214     }
215
216     /**
217      * Returns the update RunnableQueue.
218      */

219     public RunnableQueue getUpdateRunnableQueue() {
220         return updateRunnableQueue;
221     }
222
223     /**
224      * Returns the repaint manager.
225      */

226     public RepaintManager getRepaintManager() {
227         return repaintManager;
228     }
229
230     /**
231      * Returns the GVT update tracker.
232      */

233     public UpdateTracker getUpdateTracker() {
234         return updateTracker;
235     }
236
237     /**
238      * Returns the current Document.
239      */

240     public Document JavaDoc getDocument() {
241         return document;
242     }
243
244     /**
245      * Returns the scripting environment.
246      */

247     public ScriptingEnvironment getScriptingEnvironment() {
248         return scriptingEnvironment;
249     }
250
251     /**
252      * Tells whether the update manager is currently running.
253      */

254     public synchronized boolean isRunning() {
255         return running;
256     }
257
258     /**
259      * Suspends the update manager.
260      */

261     public synchronized void suspend() {
262         // System.err.println("Suspend: " + suspendCalled + " : " + running);
263
if (updateRunnableQueue.getQueueState() == RunnableQueue.RUNNING) {
264             updateRunnableQueue.suspendExecution(false);
265         }
266         suspendCalled = true;
267     }
268
269     /**
270      * Resumes the update manager.
271      */

272     public synchronized void resume() {
273         // System.err.println("Resume: " + suspendCalled + " : " + running);
274

275         // if (suspendCalled) {
276
// UpdateManagerEvent ev = new UpdateManagerEvent
277
// (this, null, null);
278
// // FIXX: Must happen in a different thread!
279
// fireEvent(suspendedDispatcher, ev);
280
// fireEvent(resumedDispatcher, ev);
281
// }
282
if (updateRunnableQueue.getQueueState() != RunnableQueue.RUNNING) {
283             updateRunnableQueue.resumeExecution();
284         }
285     }
286
287     /**
288      * Interrupts the manager tasks.
289      */

290     public synchronized void interrupt() {
291         if (updateRunnableQueue.getThread() == null)
292             return;
293
294           // Preempt to cancel the pending tasks
295
updateRunnableQueue.preemptLater(new Runnable JavaDoc() {
296                 public void run() {
297                     synchronized (UpdateManager.this) {
298                         if (started) {
299                             dispatchSVGUnLoadEvent();
300                         } else {
301                             running = false;
302                             scriptingEnvironment.interrupt();
303                             updateRunnableQueue.getThread().halt();
304                         }
305                     }
306                 }
307             });
308         resume();
309     }
310
311     /**
312      * Dispatches an 'SVGUnLoad' event to the document.
313      * This method interrupts the update manager threads.
314      * NOTE: this method must be called outside the update thread.
315      */

316     public void dispatchSVGUnLoadEvent() {
317         if (!started) {
318             throw new IllegalStateException JavaDoc("UpdateManager not started.");
319         }
320
321         // Invoke first to cancel the pending tasks
322
updateRunnableQueue.preemptLater(new Runnable JavaDoc() {
323                 public void run() {
324                     synchronized (UpdateManager.this) {
325                         Event JavaDoc evt =
326                             ((DocumentEvent JavaDoc)document).createEvent("SVGEvents");
327                         evt.initEvent("SVGUnload", false, false);
328                         ((EventTarget JavaDoc)(document.getDocumentElement())).
329                             dispatchEvent(evt);
330                         running = false;
331
332                         // Now shut everything down and disconnect
333
// everything before we send the
334
// UpdateMangerStopped event.
335
scriptingEnvironment.interrupt();
336                         updateRunnableQueue.getThread().halt();
337                         bridgeContext.dispose();
338
339                         // Send the UpdateManagerStopped event.
340
UpdateManagerEvent ev = new UpdateManagerEvent
341                             (UpdateManager.this, null, null);
342                         fireEvent(stoppedDispatcher, ev);
343                     }
344                 }
345             });
346         resume();
347     }
348
349     /**
350      * Updates the rendering buffer. Only to be called from the
351      * update thread.
352      * @param u2d The user to device transform.
353      * @param dbr Whether the double buffering should be used.
354      * @param aoi The area of interest in the renderer space units.
355      * @param width The offscreen buffer width.
356      * @param height The offscreen buffer height.
357      */

358     public void updateRendering(AffineTransform JavaDoc u2d,
359                                 boolean dbr,
360                                 Shape JavaDoc aoi,
361                                 int width,
362                                 int height) {
363         repaintManager.setupRenderer(u2d,dbr,aoi,width,height);
364         List JavaDoc l = new ArrayList JavaDoc(1);
365         l.add(aoi);
366         updateRendering(l, false);
367     }
368
369     /**
370      * Updates the rendering buffer. Only to be called from the
371      * update thread.
372      * @param u2d The user to device transform.
373      * @param dbr Whether the double buffering should be used.
374      * @param cpt If the canvas painting transform should be cleared
375      * when the update complets
376      * @param aoi The area of interest in the renderer space units.
377      * @param width The offscreen buffer width.
378      * @param height The offscreen buffer height.
379      */

380     public void updateRendering(AffineTransform JavaDoc u2d,
381                                 boolean dbr,
382                                 boolean cpt,
383                                 Shape JavaDoc aoi,
384                                 int width,
385                                 int height) {
386         repaintManager.setupRenderer(u2d,dbr,aoi,width,height);
387         List JavaDoc l = new ArrayList JavaDoc(1);
388         l.add(aoi);
389         updateRendering(l, cpt);
390     }
391
392     /**
393      * Updates the rendering buffer.
394      * @param areas List of areas of interest in rederer space units.
395      * @param clearPaintingTransform Indicates if the painting transform
396      * should be cleared as a result of this update.
397      */

398     protected void updateRendering(List JavaDoc areas,
399                                    boolean clearPaintingTransform) {
400         try {
401             UpdateManagerEvent ev = new UpdateManagerEvent
402                 (this, repaintManager.getOffScreen(), null);
403             fireEvent(updateStartedDispatcher, ev);
404
405             Collection JavaDoc c = repaintManager.updateRendering(areas);
406             List JavaDoc l = new ArrayList JavaDoc(c);
407
408             ev = new UpdateManagerEvent
409                 (this, repaintManager.getOffScreen(),
410                  l, clearPaintingTransform);
411             fireEvent(updateCompletedDispatcher, ev);
412         } catch (ThreadDeath JavaDoc td) {
413             UpdateManagerEvent ev = new UpdateManagerEvent
414                 (this, null, null);
415             fireEvent(updateFailedDispatcher, ev);
416             throw td;
417         } catch (Throwable JavaDoc t) {
418             UpdateManagerEvent ev = new UpdateManagerEvent
419                 (this, null, null);
420             fireEvent(updateFailedDispatcher, ev);
421         }
422     }
423
424     /**
425      * This tracks when the rendering first got 'out of date'
426      * with respect to the document.
427      */

428     long outOfDateTime=0;
429
430     /**
431      * Repaints the dirty areas, if needed.
432      */

433     protected void repaint() {
434         if (!updateTracker.hasChanged())
435             return;
436         long ctime = System.currentTimeMillis();
437         if (ctime-outOfDateTime < MIN_REPAINT_TIME) {
438             // We very recently did a repaint check if other
439
// repaint runnables are pending.
440
synchronized (updateRunnableQueue.getIteratorLock()) {
441                 Iterator JavaDoc i = updateRunnableQueue.iterator();
442                 while (i.hasNext())
443                     if (!(i.next() instanceof NoRepaintRunnable))
444                         // have a pending repaint runnable so we
445
// will skip this repaint and we will let
446
// the next one pick it up.
447
return;
448                 
449             }
450         }
451         
452         List JavaDoc dirtyAreas = updateTracker.getDirtyAreas();
453         updateTracker.clear();
454         if (dirtyAreas != null) {
455             updateRendering(dirtyAreas, false);
456         }
457         outOfDateTime = 0;
458     }
459
460
461     /**
462      * Adds a UpdateManagerListener to this UpdateManager.
463      */

464     public void addUpdateManagerListener(UpdateManagerListener l) {
465         listeners.add(l);
466     }
467
468     /**
469      * Removes a UpdateManagerListener from this UpdateManager.
470      */

471     public void removeUpdateManagerListener(UpdateManagerListener l) {
472         listeners.remove(l);
473     }
474
475     protected void fireEvent(Dispatcher dispatcher, Object JavaDoc event) {
476         EventDispatcher.fireEvent(dispatcher, listeners, event, false);
477     }
478
479
480     /**
481      * Dispatches a UpdateManagerEvent to notify that the manager was
482      * started
483      */

484     static Dispatcher startedDispatcher = new Dispatcher() {
485             public void dispatch(Object JavaDoc listener,
486                                  Object JavaDoc event) {
487                 ((UpdateManagerListener)listener).managerStarted
488                     ((UpdateManagerEvent)event);
489             }
490         };
491
492     /**
493      * Dispatches a UpdateManagerEvent to notify that the manager was
494      * stopped.
495      */

496     static Dispatcher stoppedDispatcher = new Dispatcher() {
497             public void dispatch(Object JavaDoc listener,
498                                  Object JavaDoc event) {
499                 ((UpdateManagerListener)listener).managerStopped
500                     ((UpdateManagerEvent)event);
501             }
502         };
503
504     /**
505      * Dispatches a UpdateManagerEvent to notify that the manager was
506      * suspended.
507      */

508     static Dispatcher suspendedDispatcher = new Dispatcher() {
509             public void dispatch(Object JavaDoc listener,
510                                  Object JavaDoc event) {
511                 ((UpdateManagerListener)listener).managerSuspended
512                     ((UpdateManagerEvent)event);
513             }
514         };
515
516     /**
517      * Dispatches a UpdateManagerEvent to notify that the manager was
518      * resumed.
519      */

520     static Dispatcher resumedDispatcher = new Dispatcher() {
521             public void dispatch(Object JavaDoc listener,
522                                  Object JavaDoc event) {
523                 ((UpdateManagerListener)listener).managerResumed
524                     ((UpdateManagerEvent)event);
525             }
526         };
527
528     /**
529      * Dispatches a UpdateManagerEvent to notify that an update
530      * started
531      */

532     static Dispatcher updateStartedDispatcher = new Dispatcher() {
533             public void dispatch(Object JavaDoc listener,
534                                  Object JavaDoc event) {
535                 ((UpdateManagerListener)listener).updateStarted
536                     ((UpdateManagerEvent)event);
537             }
538         };
539
540     /**
541      * Dispatches a UpdateManagerEvent to notify that an update
542      * completed
543      */

544     static Dispatcher updateCompletedDispatcher = new Dispatcher() {
545             public void dispatch(Object JavaDoc listener,
546                                  Object JavaDoc event) {
547                 ((UpdateManagerListener)listener).updateCompleted
548                     ((UpdateManagerEvent)event);
549             }
550         };
551
552     /**
553      * Dispatches a UpdateManagerEvent to notify that an update
554      * failed
555      */

556     static Dispatcher updateFailedDispatcher = new Dispatcher() {
557             public void dispatch(Object JavaDoc listener,
558                                  Object JavaDoc event) {
559                 ((UpdateManagerListener)listener).updateFailed
560                     ((UpdateManagerEvent)event);
561             }
562         };
563
564
565
566     // RunnableQueue.RunHandler /////////////////////////////////////////
567
protected RunnableQueue.RunHandler createRunHandler() {
568         return new UpdateManagerRunHander();
569     }
570
571     protected class UpdateManagerRunHander
572         extends RunnableQueue.RunHandlerAdapter {
573
574         public void runnableStart(RunnableQueue rq, Runnable JavaDoc r) {
575             if (running && !(r instanceof NoRepaintRunnable)) {
576                 // Mark the document as updated when the
577
// runnable starts.
578
if (outOfDateTime == 0)
579                     outOfDateTime = System.currentTimeMillis();
580             }
581         }
582         
583
584         /**
585          * Called when the given Runnable has just been invoked and
586          * has returned.
587          */

588         public void runnableInvoked(RunnableQueue rq, Runnable JavaDoc r) {
589             if (running && !(r instanceof NoRepaintRunnable)) {
590                 repaint();
591             }
592         }
593         
594         /**
595          * Called when the execution of the queue has been suspended.
596          */

597         public void executionSuspended(RunnableQueue rq) {
598             synchronized (UpdateManager.this) {
599                 // System.err.println("Suspended: " + suspendCalled);
600
if (suspendCalled) {
601                     running = false;
602                     UpdateManagerEvent ev = new UpdateManagerEvent
603                         (this, null, null);
604                     fireEvent(suspendedDispatcher, ev);
605                 }
606             }
607         }
608         
609         /**
610          * Called when the execution of the queue has been resumed.
611          */

612         public void executionResumed(RunnableQueue rq) {
613             synchronized (UpdateManager.this) {
614                 // System.err.println("Resumed: " + suspendCalled +
615
// " : " + running);
616
if (suspendCalled && !running) {
617                     running = true;
618                     suspendCalled = false;
619
620                     UpdateManagerEvent ev = new UpdateManagerEvent
621                         (this, null, null);
622                     fireEvent(resumedDispatcher, ev);
623                 }
624             }
625         }
626     }
627 }
628
Popular Tags