KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > internal > databinding > provisional > swt > CompositeUpdater


1 /*******************************************************************************
2  * Copyright (c) 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * Boris Bokowski, IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jface.internal.databinding.provisional.swt;
12
13 import org.eclipse.core.databinding.observable.ChangeEvent;
14 import org.eclipse.core.databinding.observable.IChangeListener;
15 import org.eclipse.core.databinding.observable.IObservable;
16 import org.eclipse.core.databinding.observable.ObservableTracker;
17 import org.eclipse.core.databinding.observable.list.IListChangeListener;
18 import org.eclipse.core.databinding.observable.list.IObservableList;
19 import org.eclipse.core.databinding.observable.list.ListChangeEvent;
20 import org.eclipse.core.databinding.observable.list.ListDiffEntry;
21 import org.eclipse.swt.events.DisposeEvent;
22 import org.eclipse.swt.events.DisposeListener;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Widget;
25
26 /**
27  * NON-API - This class can be used to update a composite with automatic dependency tracking.
28  * @since 1.1
29  *
30  */

31 public abstract class CompositeUpdater {
32
33     private class UpdateRunnable implements Runnable JavaDoc, IChangeListener {
34         private Widget widget;
35         Object JavaDoc element;
36
37         private boolean dirty = true;
38
39         private IObservable[] dependencies = new IObservable[0];
40
41         UpdateRunnable(Widget widget, Object JavaDoc element) {
42             this.widget = widget;
43             this.element = element;
44         }
45
46         // Runnable implementation. This method runs at most once per repaint
47
// whenever the
48
// value gets marked as dirty.
49
public void run() {
50             if (theComposite != null && !theComposite.isDisposed()
51                     && widget != null && !widget.isDisposed()) {
52                 updateIfNecessary();
53             }
54         }
55
56         private void updateIfNecessary() {
57             if (dirty) {
58                 dependencies = ObservableTracker.runAndMonitor(new Runnable JavaDoc() {
59                     public void run() {
60                         updateWidget(widget, element);
61                     }
62                 }, this, null);
63                 dirty = false;
64             }
65         }
66
67         // IChangeListener implementation (listening to any dependency)
68
public void handleChange(ChangeEvent event) {
69             // Whenever this updator becomes dirty, schedule the run() method
70
makeDirty();
71         }
72
73         protected final void makeDirty() {
74             if (!dirty) {
75                 dirty = true;
76                 stopListening();
77                 if (!theComposite.isDisposed()) {
78                     SWTUtil.runOnce(theComposite.getDisplay(), this);
79                 }
80             }
81         }
82
83         private void stopListening() {
84             // Stop listening for dependency changes
85
for (int i = 0; i < dependencies.length; i++) {
86                 IObservable observable = dependencies[i];
87
88                 observable.removeChangeListener(this);
89             }
90         }
91     }
92
93     private class PrivateInterface implements DisposeListener,
94             IListChangeListener {
95
96         // DisposeListener implementation
97
public void widgetDisposed(DisposeEvent e) {
98             CompositeUpdater.this.dispose();
99         }
100
101         public void handleListChange(ListChangeEvent event) {
102             ListDiffEntry[] diffs = event.diff.getDifferences();
103             for (int i = 0; i < diffs.length; i++) {
104                 ListDiffEntry listDiffEntry = diffs[i];
105                 if (listDiffEntry.isAddition()) {
106                     Widget newChild = createWidget(listDiffEntry.getPosition());
107                     final UpdateRunnable updateRunnable = new UpdateRunnable(newChild, listDiffEntry
108                             .getElement());
109                     newChild.setData(updateRunnable);
110                     updateRunnable.updateIfNecessary();
111                 } else {
112                     theComposite.getChildren()[listDiffEntry.getPosition()]
113                             .dispose();
114                 }
115             }
116             theComposite.layout();
117         }
118
119     }
120
121     private PrivateInterface privateInterface = new PrivateInterface();
122
123     private Composite theComposite;
124
125     private IObservableList model;
126
127     /**
128      * Creates an updater for the given control and list. For each element of
129      * the list, a child widget of the composite will be created using
130      * {@link #createWidget(int)}.
131      *
132      * @param toUpdate
133      * composite to update
134      * @param model
135      * an observable list to track
136      */

137     public CompositeUpdater(Composite toUpdate, IObservableList model) {
138         this.theComposite = toUpdate;
139         this.model = model;
140
141         model.addListChangeListener(privateInterface);
142         theComposite.addDisposeListener(privateInterface);
143     }
144
145     /**
146      * This is called automatically when the control is disposed. It may also be
147      * called explicitly to remove this updator from the control. Subclasses
148      * will normally extend this method to detach any listeners they attached in
149      * their constructor.
150      */

151     public void dispose() {
152         theComposite.removeDisposeListener(privateInterface);
153         model.removeListChangeListener(privateInterface);
154     }
155
156     /**
157      * Creates a new child widget for the target composite at the given index.
158      *
159      * <p>
160      * Subclasses should implement this method to provide the code that creates
161      * a child widget at a specific index. Note that
162      * {@link #updateWidget(Widget, Object)} will be called after this method
163      * returns. Only those properties of the widget that don't change over time
164      * should be set in this method.
165      * </p>
166      *
167      * @param index
168      * the at which to create the widget
169      * @return the widget
170      */

171     protected abstract Widget createWidget(int index);
172
173     /**
174      * Updates the given widget based on the element found in the model list.
175      * This method will be invoked once after the widget is created, and once
176      * before any repaint during which the control is visible and dirty.
177      *
178      * <p>
179      * Subclasses should implement this method to provide any code that changes
180      * the appearance of the widget.
181      * </p>
182      *
183      * @param widget
184      * the widget to update
185      * @param element
186      * the element associated with the widget
187      */

188     protected abstract void updateWidget(Widget widget, Object JavaDoc element);
189
190 }
191
Popular Tags