1 /*
   2  * Copyright (c) 1997, 2018, 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 
  26 package javax.swing;
  27 
  28 import javax.swing.event.EventListenerList;
  29 import javax.swing.event.ListDataListener;
  30 import javax.swing.event.ListDataEvent;
  31 import java.io.Serializable;
  32 import java.util.function.BiConsumer;
  33 import java.util.EventListener;
  34 
  35 /**
  36  * The abstract definition for the data model that provides
  37  * a <code>List</code> with its contents.
  38  * <p>
  39  * <strong>Warning:</strong>
  40  * Serialized objects of this class will not be compatible with
  41  * future Swing releases. The current serialization support is
  42  * appropriate for short term storage or RMI between applications running
  43  * the same version of Swing.  As of 1.4, support for long term storage
  44  * of all JavaBeans&trade;
  45  * has been added to the <code>java.beans</code> package.
  46  * Please see {@link java.beans.XMLEncoder}.
  47  *
  48  * @param <E> the type of the elements of this model
  49  *
  50  * @author Hans Muller
  51  * @since 1.2
  52  */
  53 @SuppressWarnings("serial") // Same-version serialization only
  54 public abstract class AbstractListModel<E> implements ListModel<E>, Serializable
  55 {
  56     /**
  57      * The listener list.
  58      */
  59     protected EventListenerList listenerList = new EventListenerList();
  60 
  61 
  62     /**
  63      * Adds a listener to the list that's notified each time a change
  64      * to the data model occurs.
  65      *
  66      * @param l the <code>ListDataListener</code> to be added
  67      */
  68     public void addListDataListener(ListDataListener l) {
  69         listenerList.add(ListDataListener.class, l);
  70     }
  71 
  72 
  73     /**
  74      * Removes a listener from the list that's notified each time a
  75      * change to the data model occurs.
  76      *
  77      * @param l the <code>ListDataListener</code> to be removed
  78      */
  79     public void removeListDataListener(ListDataListener l) {
  80         listenerList.remove(ListDataListener.class, l);
  81     }
  82 
  83 
  84     /**
  85      * Returns an array of all the list data listeners
  86      * registered on this <code>AbstractListModel</code>.
  87      *
  88      * @return all of this model's <code>ListDataListener</code>s,
  89      *         or an empty array if no list data listeners
  90      *         are currently registered
  91      *
  92      * @see #addListDataListener
  93      * @see #removeListDataListener
  94      *
  95      * @since 1.4
  96      */
  97     public ListDataListener[] getListDataListeners() {
  98         return listenerList.getListeners(ListDataListener.class);
  99     }
 100 
 101 
 102     /**
 103      * The workhorse function which does the job of calling the listeners
 104      * interested in listening to the appropriate event that has occurred.
 105      * Functions fireContentsChanged, fireIntervalAdded and fireIntervalRemoved
 106      * call this function with appropriate arguments filled.
 107      */
 108     private void fireUpdates(Object source, int index0, int index1, int eventType, 
 109                             BiConsumer<ListDataListener, ListDataEvent> func) {
 110         Object[] listeners = listenerList.getListenerList();
 111         ListDataEvent e = null;
 112 
 113         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 114             if (listeners[i] == ListDataListener.class) {
 115                 if (e == null) {
 116                     e = new ListDataEvent(source, eventType, index0, index1);
 117                 }
 118                 func.accept((ListDataListener)listeners[i+1], e);
 119             }
 120         }
 121     }
 122 
 123 
 124     /**
 125      * <code>AbstractListModel</code> subclasses must call this method
 126      * <b>after</b>
 127      * one or more elements of the list change.  The changed elements
 128      * are specified by the closed interval index0, index1 -- the endpoints
 129      * are included.  Note that
 130      * index0 need not be less than or equal to index1.
 131      *
 132      * @param source the <code>ListModel</code> that changed, typically "this"
 133      * @param index0 one end of the new interval
 134      * @param index1 the other end of the new interval
 135      * @see EventListenerList
 136      * @see DefaultListModel
 137      */
 138     protected void fireContentsChanged(Object source, int index0, int index1)
 139     {
 140         fireUpdates(source, index0, index1, ListDataEvent.CONTENTS_CHANGED, 
 141                 (l, e) -> l.contentsChanged(e));
 142     }
 143 
 144 
 145     /**
 146      * <code>AbstractListModel</code> subclasses must call this method
 147      * <b>after</b>
 148      * one or more elements are added to the model.  The new elements
 149      * are specified by a closed interval index0, index1 -- the enpoints
 150      * are included.  Note that
 151      * index0 need not be less than or equal to index1.
 152      *
 153      * @param source the <code>ListModel</code> that changed, typically "this"
 154      * @param index0 one end of the new interval
 155      * @param index1 the other end of the new interval
 156      * @see EventListenerList
 157      * @see DefaultListModel
 158      */
 159     protected void fireIntervalAdded(Object source, int index0, int index1)
 160     {
 161         fireUpdates(source, index0, index1, ListDataEvent.INTERVAL_ADDED,
 162             (l, e) -> l.intervalAdded(e));
 163     }
 164 
 165 
 166     /**
 167      * <code>AbstractListModel</code> subclasses must call this method
 168      * <b>after</b> one or more elements are removed from the model.
 169      * <code>index0</code> and <code>index1</code> are the end points
 170      * of the interval that's been removed.  Note that <code>index0</code>
 171      * need not be less than or equal to <code>index1</code>.
 172      *
 173      * @param source the <code>ListModel</code> that changed, typically "this"
 174      * @param index0 one end of the removed interval,
 175      *               including <code>index0</code>
 176      * @param index1 the other end of the removed interval,
 177      *               including <code>index1</code>
 178      * @see EventListenerList
 179      * @see DefaultListModel
 180      */
 181     protected void fireIntervalRemoved(Object source, int index0, int index1)
 182     {
 183         fireUpdates(source, index0, index1, ListDataEvent.INTERVAL_REMOVED,
 184             (l, e) -> l.intervalRemoved(e));
 185     }
 186 
 187     /**
 188      * Returns an array of all the objects currently registered as
 189      * <code><em>Foo</em>Listener</code>s
 190      * upon this model.
 191      * <code><em>Foo</em>Listener</code>s
 192      * are registered using the <code>add<em>Foo</em>Listener</code> method.
 193      * <p>
 194      * You can specify the <code>listenerType</code> argument
 195      * with a class literal, such as <code><em>Foo</em>Listener.class</code>.
 196      * For example, you can query a list model
 197      * <code>m</code>
 198      * for its list data listeners
 199      * with the following code:
 200      *
 201      * <pre>ListDataListener[] ldls = (ListDataListener[])(m.getListeners(ListDataListener.class));</pre>
 202      *
 203      * If no such listeners exist,
 204      * this method returns an empty array.
 205      *
 206      * @param <T> the type of {@code EventListener} class being requested
 207      * @param listenerType  the type of listeners requested;
 208      *          this parameter should specify an interface
 209      *          that descends from <code>java.util.EventListener</code>
 210      * @return an array of all objects registered as
 211      *          <code><em>Foo</em>Listener</code>s
 212      *          on this model,
 213      *          or an empty array if no such
 214      *          listeners have been added
 215      * @exception ClassCastException if <code>listenerType</code> doesn't
 216      *          specify a class or interface that implements
 217      *          <code>java.util.EventListener</code>
 218      *
 219      * @see #getListDataListeners
 220      *
 221      * @since 1.3
 222      */
 223     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 224         return listenerList.getListeners(listenerType);
 225     }
 226 }