1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.swing; 26 27 import java.util.*; 28 import java.lang.reflect.Array; 29 import 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<String> 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<Rectangle> 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 */ 93 public 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 */ run(List<T> args)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 */ run()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 @SafeVarargs 124 @SuppressWarnings("varargs") // Copying args is safe add(T... args)125 public final synchronized void add(T... args) { 126 boolean isSubmitted = true; 127 if (arguments == null) { 128 isSubmitted = false; 129 arguments = new ArrayList<T>(); 130 } 131 Collections.addAll(arguments, args); 132 if (!isSubmitted) { 133 submit(); 134 } 135 } 136 137 /** 138 * Sends this {@code Runnable} for the execution 139 * 140 * <p> 141 * This method is to be executed only from {@code add} method. 142 * 143 * <p> 144 * This implementation uses {@code SwingWorker.invokeLater}. 145 */ submit()146 protected void submit() { 147 SwingUtilities.invokeLater(this); 148 } 149 150 /** 151 * Returns accumulated arguments and flashes the arguments storage. 152 * 153 * @return accumulated arguments 154 */ flush()155 private final synchronized List<T> flush() { 156 List<T> list = arguments; 157 arguments = null; 158 return list; 159 } 160 } 161