1 /*
   2  * Copyright (c) 2005, 2006, 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&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  */
  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      */
 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     @SafeVarargs
 124     public final synchronized void add(T... args) {
 125         boolean isSubmitted = true;
 126         if (arguments == null) {
 127             isSubmitted = false;
 128             arguments = new ArrayList<T>();
 129         }
 130         Collections.addAll(arguments, args);
 131         if (!isSubmitted) {
 132             submit();
 133         }
 134     }
 135 
 136     /**
 137      * Sends this {@code Runnable} for the execution
 138      *
 139      * <p>
 140      * This method is to be executed only from {@code add} method.
 141      *
 142      * <p>
 143      * This implementation uses {@code SwingWorker.invokeLater}.
 144      */
 145     protected void submit() {
 146         SwingUtilities.invokeLater(this);
 147     }
 148 
 149     /**
 150      * Returns accumulated arguments and flashes the arguments storage.
 151      *
 152      * @return accumulated arguments
 153      */
 154     private final synchronized List<T> flush() {
 155         List<T> list = arguments;
 156         arguments = null;
 157         return list;
 158     }
 159 }