001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2015 the original author or authors.
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
020package com.puppycrawl.tools.checkstyle.gui;
021
022import javax.swing.event.EventListenerList;
023import javax.swing.event.TreeModelEvent;
024import javax.swing.event.TreeModelListener;
025
026/**
027 * An abstract implementation of the TreeTableModel interface, handling
028 * the list of listeners.
029 *
030 * <a href=
031 * "https://docs.oracle.com/cd/E48246_01/apirefs.1111/e13403/oracle/ide/controls/TreeTableModel.html">
032 * Original&nbsp;Source&nbsp;Location</a>
033 *
034 * @author Philip Milne
035 */
036public abstract class AbstractTreeTableModel implements TreeTableModel {
037
038    /**
039     * The root node of the tree table model.
040     */
041    private final Object root;
042
043    /**
044     * A list of event listeners for the tree model.
045     */
046    private final EventListenerList listenerList = new EventListenerList();
047
048    /**
049     * Initializes the root node for the tree table model.
050     *
051     * @param root Root node.
052     */
053    AbstractTreeTableModel(Object root) {
054        this.root = root;
055    }
056
057    //
058    // Default implementations for methods in the TreeModel interface.
059    //
060
061    @Override
062    public Object getRoot() {
063        return root;
064    }
065
066    @Override
067    public boolean isLeaf(Object node) {
068        return getChildCount(node) == 0;
069    }
070
071    // This is not called in the JTree's default mode: use a naive implementation.
072    @Override
073    public int getIndexOfChild(Object parent, Object child) {
074        for (int i = 0; i < getChildCount(parent); i++) {
075            if (getChild(parent, i).equals(child)) {
076                return i;
077            }
078        }
079        return -1;
080    }
081
082    @Override
083    public void addTreeModelListener(TreeModelListener listener) {
084        listenerList.add(TreeModelListener.class, listener);
085    }
086
087    @Override
088    public void removeTreeModelListener(TreeModelListener listener) {
089        listenerList.remove(TreeModelListener.class, listener);
090    }
091
092    /**
093     * Notifies all listeners that have registered interest for
094     * 'tree nodes changed' event.  The event instance
095     * is lazily created using the parameters passed into
096     * the fire method.
097     * @param source The Object responsible for generating the event.
098     * @param path An array of Object identifying the path to the parent of the modified items.
099     * @param childIndices An array of int that specifies the index values of the removed items.
100     * @param children An array of Object containing the inserted, removed, or changed objects.
101     * @see EventListenerList
102     */
103    protected void fireTreeNodesChanged(Object source, Object[] path,
104            int[] childIndices,
105            Object... children) {
106        // Guaranteed to return a non-null array
107        final Object[] listeners = listenerList.getListenerList();
108        TreeModelEvent event = null;
109        // Process the listeners last to first, notifying
110        // those that are interested in this event
111        for (int i = listeners.length - 2; i >= 0; i -= 2) {
112            if (listeners[i] == TreeModelListener.class) {
113                // Lazily create the event:
114                if (event == null) {
115                    event = new TreeModelEvent(source, path,
116                            childIndices, children);
117                }
118                ((TreeModelListener) listeners[i + 1]).treeNodesChanged(event);
119            }
120        }
121    }
122
123    /**
124     * Notify all listeners that have registered interest for
125     * 'tree nodes inserted' event.  The event instance
126     * is lazily created using the parameters passed into
127     * the fire method.
128     * @param source The Object responsible for generating the event.
129     * @param path An array of Object identifying the path to the parent of the modified items.
130     * @param childIndices An array of int that specifies the index values of the removed items.
131     * @param children An array of Object containing the inserted, removed, or changed objects.
132     * @see EventListenerList
133     */
134    protected void fireTreeNodesInserted(Object source, Object[] path,
135            int[] childIndices,
136            Object... children) {
137        // Guaranteed to return a non-null array
138        final Object[] listeners = listenerList.getListenerList();
139        TreeModelEvent event = null;
140        // Process the listeners last to first, notifying
141        // those that are interested in this event
142        for (int i = listeners.length - 2; i >= 0; i -= 2) {
143            if (listeners[i] == TreeModelListener.class) {
144                // Lazily create the event:
145                if (event == null) {
146                    event = new TreeModelEvent(source, path,
147                            childIndices, children);
148                }
149                ((TreeModelListener) listeners[i + 1]).treeNodesInserted(event);
150            }
151        }
152    }
153
154    /**
155     * Notify all listeners that have registered interest for
156     * 'tree nodes removed' event.  The event instance
157     * is lazily created using the parameters passed into
158     * the fire method.
159     * @param source The Object responsible for generating the event.
160     * @param path An array of Object identifying the path to the parent of the modified items.
161     * @param childIndices An array of int that specifies the index values of the removed items.
162     * @param children An array of Object containing the inserted, removed, or changed objects.
163     * @see EventListenerList
164     */
165    protected void fireTreeNodesRemoved(Object source, Object[] path,
166            int[] childIndices,
167            Object... children) {
168        // Guaranteed to return a non-null array
169        final Object[] listeners = listenerList.getListenerList();
170        TreeModelEvent event = null;
171        // Process the listeners last to first, notifying
172        // those that are interested in this event
173        for (int i = listeners.length - 2; i >= 0; i -= 2) {
174            if (listeners[i] == TreeModelListener.class) {
175                // Lazily create the event:
176                if (event == null) {
177                    event = new TreeModelEvent(source, path,
178                            childIndices, children);
179                }
180                ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(event);
181            }
182        }
183    }
184
185    /**
186     * Notify all listeners that have registered interest for
187     * 'tree structure changed' event.  The event instance
188     * is lazily created using the parameters passed into
189     * the fire method.
190     * @param source The Object responsible for generating the event.
191     * @param path An array of Object identifying the path to the parent of the modified items.
192     * @param childIndices An array of int that specifies the index values of the removed items.
193     * @param children An array of Object containing the inserted, removed, or changed objects.
194     * @see EventListenerList
195     */
196    void fireTreeStructureChanged(Object source, Object[] path,
197            int[] childIndices,
198            Object... children) {
199        // Guaranteed to return a non-null array
200        final Object[] listeners = listenerList.getListenerList();
201        TreeModelEvent event = null;
202        // Process the listeners last to first, notifying
203        // those that are interested in this event
204        for (int i = listeners.length - 2; i >= 0; i -= 2) {
205            if (listeners[i] == TreeModelListener.class) {
206                // Lazily create the event:
207                if (event == null) {
208                    event = new TreeModelEvent(source, path,
209                            childIndices, children);
210                }
211                ((TreeModelListener) listeners[i + 1]).treeStructureChanged(event);
212            }
213        }
214    }
215
216    //
217    // Default implementations for methods in the TreeTableModel interface.
218    //
219
220    @Override
221    public Class<?> getColumnClass(int column) {
222        return Object.class;
223    }
224
225    /** By default, make the column with the Tree in it the only editable one.
226     *  Making this column editable causes the JTable to forward mouse
227     *  and keyboard events in the Tree column to the underlying JTree.
228     */
229    @Override
230    public boolean isCellEditable(int column) {
231        return getColumnClass(column) == TreeTableModel.class;
232    }
233}