1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.gui;
21  
22  import javax.swing.event.EventListenerList;
23  import javax.swing.event.TreeModelEvent;
24  import javax.swing.event.TreeModelListener;
25  import javax.swing.tree.TreeModel;
26  import javax.swing.tree.TreePath;
27  
28  import com.puppycrawl.tools.checkstyle.api.DetailAST;
29  import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode;
30  
31  /**
32   * The model that backs the parse tree in the GUI.
33   *
34   */
35  public class ParseTreeTableModel implements TreeModel {
36  
37      /** Presentation model. */
38      private final ParseTreeTablePresentation pModel;
39  
40      /**
41       * A list of event listeners for the tree model.
42       */
43      private final EventListenerList listenerList = new EventListenerList();
44  
45      /**
46       * Initialise pModel.
47       * @param parseTree DetailAST parse tree.
48       */
49      public ParseTreeTableModel(DetailAST parseTree) {
50          pModel = new ParseTreeTablePresentation(parseTree);
51          setParseTree(parseTree);
52      }
53  
54      /**
55       * Sets parse tree.
56       * @param parseTree DetailAST parse tree.
57       */
58      protected final void setParseTree(DetailAST parseTree) {
59          pModel.setParseTree(parseTree);
60          final Object[] path = {pModel.getRoot()};
61          // no need to setup remaining info, as the call results in a
62          // table structure changed event anyway - we just pass nulls
63          fireTreeStructureChanged(this, path, null, (Object[]) null);
64      }
65  
66      /**
67       * Set parse mode.
68       * @param mode ParseMode enum
69       */
70      protected void setParseMode(ParseMode mode) {
71          pModel.setParseMode(mode);
72      }
73  
74      /**
75       * Returns number of available column.
76       * @return the number of available column.
77       */
78      public int getColumnCount() {
79          return pModel.getColumnCount();
80      }
81  
82      /**
83       * Returns column name of specified column number.
84       * @param column the column number
85       * @return the name for column number {@code column}.
86       */
87      public String getColumnName(int column) {
88          return pModel.getColumnName(column);
89      }
90  
91      /**
92       * Returns type of specified column number.
93       * @param column the column number
94       * @return the type for column number {@code column}.
95       */
96      // -@cs[ForbidWildcardAsReturnType] We need to satisfy javax.swing.table.AbstractTableModel
97      // public Class<?> getColumnClass(int columnIndex) {...}
98      public Class<?> getColumnClass(int column) {
99          return pModel.getColumnClass(column);
100     }
101 
102     /**
103      * Returns the value to be displayed for node at column number.
104      * @param node the node
105      * @param column the column number
106      * @return the value to be displayed for node {@code node},
107      *     at column number {@code column}.
108      */
109     public Object getValueAt(Object node, int column) {
110         return pModel.getValueAt(node, column);
111     }
112 
113     @Override
114     public Object getChild(Object parent, int index) {
115         return pModel.getChild(parent, index);
116     }
117 
118     @Override
119     public int getChildCount(Object parent) {
120         return pModel.getChildCount(parent);
121     }
122 
123     @Override
124     public void valueForPathChanged(TreePath path, Object newValue) {
125         // No Code, as tree is read-only
126     }
127 
128     @Override
129     public Object getRoot() {
130         return pModel.getRoot();
131     }
132 
133     @Override
134     public boolean isLeaf(Object node) {
135         return pModel.isLeaf(node);
136     }
137 
138     // This is not called in the JTree's default mode: use a naive implementation.
139     @Override
140     public int getIndexOfChild(Object parent, Object child) {
141         return pModel.getIndexOfChild(parent, child);
142     }
143 
144     @Override
145     public void addTreeModelListener(TreeModelListener listener) {
146         listenerList.add(TreeModelListener.class, listener);
147     }
148 
149     @Override
150     public void removeTreeModelListener(TreeModelListener listener) {
151         listenerList.remove(TreeModelListener.class, listener);
152     }
153 
154     /**
155      * Notify all listeners that have registered interest for
156      * 'tree structure changed' 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     private void fireTreeStructureChanged(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]).treeStructureChanged(event);
181             }
182         }
183     }
184 
185     /**
186      * Indicates whether the the value for node {@code node},
187      * at column number {@code column} is editable.
188      *
189      * @param column the column number
190      * @return true if editable
191      */
192     public boolean isCellEditable(int column) {
193         return pModel.isCellEditable(column);
194     }
195 
196 }