blob: caed8a31a303db9350a589477ace05a7e71305eb [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package sun.swing;
26
27import java.util.*;
28import java.lang.reflect.Array;
29import javax.swing.SwingUtilities;
30
31/**
32 * An abstract class to be used in the cases where we need {@code Runnable}
33 * to perform some actions on an appendable set of data.
34 * The set of data might be appended after the {@code Runnable} is
35 * sent for the execution. Usually such {@code Runnables} are sent to
36 * the EDT.
37 *
38 * <p>
39 * Usage example:
40 *
41 * <p>
42 * Say we want to implement JLabel.setText(String text) which sends
43 * {@code text} string to the JLabel.setTextImpl(String text) on the EDT.
44 * In the event JLabel.setText is called rapidly many times off the EDT
45 * we will get many updates on the EDT but only the last one is important.
46 * (Every next updates overrides the previous one.)
47 * We might want to implement this {@code setText} in a way that only
48 * the last update is delivered.
49 * <p>
50 * Here is how one can do this using {@code AccumulativeRunnable}:
51 * <pre>
52 * AccumulativeRunnable<String> doSetTextImpl =
53 * new AccumulativeRunnable<String>() {
54 * @Override
55 * protected void run(List&lt;String&gt; args) {
56 * //set to the last string being passed
57 * setTextImpl(args.get(args.size() - 1));
58 * }
59 * }
60 * void setText(String text) {
61 * //add text and send for the execution if needed.
62 * doSetTextImpl.add(text);
63 * }
64 * </pre>
65 *
66 * <p>
67 * Say we want want to implement addDirtyRegion(Rectangle rect)
68 * which sends this region to the
69 * handleDirtyRegions(List<Rect> regiouns) on the EDT.
70 * addDirtyRegions better be accumulated before handling on the EDT.
71 *
72 * <p>
73 * Here is how it can be implemented using AccumulativeRunnable:
74 * <pre>
75 * AccumulativeRunnable<Rectangle> doHandleDirtyRegions =
76 * new AccumulativeRunnable<Rectangle>() {
77 * @Override
78 * protected void run(List&lt;Rectangle&gt; args) {
79 * handleDirtyRegions(args);
80 * }
81 * };
82 * void addDirtyRegion(Rectangle rect) {
83 * doHandleDirtyRegions.add(rect);
84 * }
85 * </pre>
86 *
87 * @author Igor Kushnirskiy
88 *
89 * @param <T> the type this {@code Runnable} accumulates
90 *
91 * @since 1.6
92 */
93public abstract class AccumulativeRunnable<T> implements Runnable {
94 private List<T> arguments = null;
95
96 /**
97 * Equivalent to {@code Runnable.run} method with the
98 * accumulated arguments to process.
99 *
100 * @param args accumulated argumets to process.
101 */
102 protected abstract void run(List<T> args);
103
104 /**
105 * {@inheritDoc}
106 *
107 * <p>
108 * This implementation calls {@code run(List<T> args)} mehtod
109 * with the list of accumulated arguments.
110 */
111 public final void run() {
112 run(flush());
113 }
114
115 /**
116 * appends arguments and sends this {@cod Runnable} for the
117 * execution if needed.
118 * <p>
119 * This implementation uses {@see #submit} to send this
120 * {@code Runnable} for execution.
121 * @param args the arguments to accumulate
122 */
123 public final synchronized void add(T... args) {
124 boolean isSubmitted = true;
125 if (arguments == null) {
126 isSubmitted = false;
127 arguments = new ArrayList<T>();
128 }
129 Collections.addAll(arguments, args);
130 if (!isSubmitted) {
131 submit();
132 }
133 }
134
135 /**
136 * Sends this {@code Runnable} for the execution
137 *
138 * <p>
139 * This method is to be executed only from {@code add} method.
140 *
141 * <p>
142 * This implementation uses {@code SwingWorker.invokeLater}.
143 */
144 protected void submit() {
145 SwingUtilities.invokeLater(this);
146 }
147
148 /**
149 * Returns accumulated arguments and flashes the arguments storage.
150 *
151 * @return accumulated arguments
152 */
153 private final synchronized List<T> flush() {
154 List<T> list = arguments;
155 arguments = null;
156 return list;
157 }
158}