001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2002  Oliver Burn
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020/*
021 * %W% %E%
022 *
023 * Copyright 1997, 1998 Sun Microsystems, Inc. All Rights Reserved.
024 *
025 * Redistribution and use in source and binary forms, with or
026 * without modification, are permitted provided that the following
027 * conditions are met:
028 *
029 * - Redistributions of source code must retain the above copyright
030 *   notice, this list of conditions and the following disclaimer.
031 *
032 * - Redistribution in binary form must reproduce the above
033 *   copyright notice, this list of conditions and the following
034 *   disclaimer in the documentation and/or other materials
035 *   provided with the distribution.
036 *
037 * Neither the name of Sun Microsystems, Inc. or the names of
038 * contributors may be used to endorse or promote products derived
039 * from this software without specific prior written permission.
040 *
041 * This software is provided "AS IS," without a warranty of any
042 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
043 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
044 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
045 * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
046 * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
047 * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE OR
048 * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
049 * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
050 * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
051 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
052 * THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
053 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
054 *
055 * You acknowledge that this software is not designed, licensed or
056 * intended for use in the design, construction, operation or
057 * maintenance of any nuclear facility.
058 */
059
060package com.puppycrawl.tools.checkstyle.gui;
061
062import javax.swing.event.EventListenerList;
063import javax.swing.event.TreeModelEvent;
064import javax.swing.event.TreeModelListener;
065import javax.swing.tree.TreePath;
066
067/**
068 * An abstract implementation of the TreeTableModel interface, handling
069 * the list of listeners.
070 *
071 * <a href="http://java.sun.com/products/jfc/tsc/articles/treetable1/index.html">Original&nbsp;Source&nbsp;Location</a>
072 *
073 * @author Philip Milne
074 */
075public abstract class AbstractTreeTableModel implements TreeTableModel
076{
077    private final Object root;
078    private final EventListenerList listenerList = new EventListenerList();
079
080    public AbstractTreeTableModel(Object root)
081    {
082        this.root = root;
083    }
084
085    //
086    // Default implmentations for methods in the TreeModel interface.
087    //
088
089    @Override
090    public Object getRoot()
091    {
092        return root;
093    }
094
095    @Override
096    public boolean isLeaf(Object node)
097    {
098        return getChildCount(node) == 0;
099    }
100
101    @Override
102    public void valueForPathChanged(TreePath path, Object newValue)
103    {
104    }
105
106    // This is not called in the JTree's default mode: use a naive implementation.
107    @Override
108    public int getIndexOfChild(Object parent, Object child)
109    {
110        for (int i = 0; i < getChildCount(parent); i++) {
111            if (getChild(parent, i).equals(child)) {
112                return i;
113            }
114        }
115        return -1;
116    }
117
118    @Override
119    public void addTreeModelListener(TreeModelListener l)
120    {
121        listenerList.add(TreeModelListener.class, l);
122    }
123
124    @Override
125    public void removeTreeModelListener(TreeModelListener l)
126    {
127        listenerList.remove(TreeModelListener.class, l);
128    }
129
130    /*
131     * Notify all listeners that have registered interest for
132     * notification on this event type.  The event instance
133     * is lazily created using the parameters passed into
134     * the fire method.
135     * @see EventListenerList
136     */
137    protected void fireTreeNodesChanged(Object source, Object[] path,
138            int[] childIndices,
139            Object[] children)
140    {
141        // Guaranteed to return a non-null array
142        final Object[] listeners = listenerList.getListenerList();
143        TreeModelEvent e = null;
144        // Process the listeners last to first, notifying
145        // those that are interested in this event
146        for (int i = listeners.length - 2; i >= 0; i -= 2) {
147            if (listeners[i] == TreeModelListener.class) {
148                // Lazily create the event:
149                if (e == null) {
150                    e = new TreeModelEvent(source, path,
151                            childIndices, children);
152                }
153                ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e);
154            }
155        }
156    }
157
158    /*
159     * Notify all listeners that have registered interest for
160     * notification on this event type.  The event instance
161     * is lazily created using the parameters passed into
162     * the fire method.
163     * @see EventListenerList
164     */
165    protected void fireTreeNodesInserted(Object source, Object[] path,
166            int[] childIndices,
167            Object[] children)
168    {
169        // Guaranteed to return a non-null array
170        final Object[] listeners = listenerList.getListenerList();
171        TreeModelEvent e = null;
172        // Process the listeners last to first, notifying
173        // those that are interested in this event
174        for (int i = listeners.length - 2; i >= 0; i -= 2) {
175            if (listeners[i] == TreeModelListener.class) {
176                // Lazily create the event:
177                if (e == null) {
178                    e = new TreeModelEvent(source, path,
179                            childIndices, children);
180                }
181                ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e);
182            }
183        }
184    }
185
186    /*
187     * Notify all listeners that have registered interest for
188     * notification on this event type.  The event instance
189     * is lazily created using the parameters passed into
190     * the fire method.
191     * @see EventListenerList
192     */
193    protected void fireTreeNodesRemoved(Object source, Object[] path,
194            int[] childIndices,
195            Object[] children)
196    {
197        // Guaranteed to return a non-null array
198        final Object[] listeners = listenerList.getListenerList();
199        TreeModelEvent e = null;
200        // Process the listeners last to first, notifying
201        // those that are interested in this event
202        for (int i = listeners.length - 2; i >= 0; i -= 2) {
203            if (listeners[i] == TreeModelListener.class) {
204                // Lazily create the event:
205                if (e == null) {
206                    e = new TreeModelEvent(source, path,
207                            childIndices, children);
208                }
209                ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e);
210            }
211        }
212    }
213
214    /*
215     * Notify all listeners that have registered interest for
216     * notification on this event type.  The event instance
217     * is lazily created using the parameters passed into
218     * the fire method.
219     * @see EventListenerList
220     */
221    protected void fireTreeStructureChanged(Object source, Object[] path,
222            int[] childIndices,
223            Object[] children)
224    {
225        // Guaranteed to return a non-null array
226        final Object[] listeners = listenerList.getListenerList();
227        TreeModelEvent e = null;
228        // Process the listeners last to first, notifying
229        // those that are interested in this event
230        for (int i = listeners.length - 2; i >= 0; i -= 2) {
231            if (listeners[i] == TreeModelListener.class) {
232                // Lazily create the event:
233                if (e == null) {
234                    e = new TreeModelEvent(source, path,
235                            childIndices, children);
236                }
237                ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e);
238            }
239        }
240    }
241
242    //
243    // Default impelmentations for methods in the TreeTableModel interface.
244    //
245
246    @Override
247    public Class<?> getColumnClass(int column)
248    {
249        return Object.class;
250    }
251
252    /** By default, make the column with the Tree in it the only editable one.
253     *  Making this column editable causes the JTable to forward mouse
254     *  and keyboard events in the Tree column to the underlying JTree.
255     */
256    @Override
257    public boolean isCellEditable(Object node, int column)
258    {
259        return getColumnClass(column) == TreeTableModel.class;
260    }
261
262    @Override
263    public void setValueAt(Object value, Object node, int column)
264    {
265    }
266
267
268    // Left to be implemented in the subclass:
269
270    /*
271     *   public Object getChild(Object parent, int index)
272     *   public int getChildCount(Object parent)
273     *   public int getColumnCount()
274     *   public String getColumnName(Object node, int column)
275     *   public Object getValueAt(Object node, int column)
276     */
277}