View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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 java.awt.BorderLayout;
23  import java.awt.FlowLayout;
24  import java.awt.GridLayout;
25  import java.awt.Toolkit;
26  import java.awt.event.ActionEvent;
27  import java.awt.event.KeyEvent;
28  import java.io.File;
29  
30  import javax.swing.AbstractAction;
31  import javax.swing.BorderFactory;
32  import javax.swing.JButton;
33  import javax.swing.JComboBox;
34  import javax.swing.JFileChooser;
35  import javax.swing.JFrame;
36  import javax.swing.JLabel;
37  import javax.swing.JOptionPane;
38  import javax.swing.JPanel;
39  import javax.swing.JScrollPane;
40  import javax.swing.JSplitPane;
41  import javax.swing.JTextArea;
42  import javax.swing.SwingConstants;
43  import javax.swing.border.Border;
44  import javax.swing.filechooser.FileFilter;
45  
46  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
47  import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode;
48  
49  /**
50   * Displays information about a parse tree.
51   * The user can change the file that is parsed and displayed
52   * using a JFileChooser.
53   *
54   * @noinspection MagicNumber
55   * @noinspectionreason MagicNumber - "magic numbers" are required to set GUI elements
56   */
57  public class MainFrame extends JFrame {
58  
59      /** A unique serial version identifier. */
60      private static final long serialVersionUID = 7970053543351871890L;
61  
62      /** The icon to show in the OS task panel. */
63      private static final String ICON = "icon.png";
64  
65      /** Checkstyle frame model. */
66      private final transient MainFrameModel model = new MainFrameModel();
67      /** Reload action. */
68      private final ReloadAction reloadAction = new ReloadAction();
69      /** Code text area. */
70      private JTextArea textArea;
71      /** Xpath text area. */
72      private JTextArea xpathTextArea;
73      /** Tree table. */
74      private TreeTable treeTable;
75  
76      /** Create a new MainFrame. */
77      public MainFrame() {
78          createContent();
79      }
80  
81      /** Create content of this MainFrame. */
82      private void createContent() {
83          setLayout(new BorderLayout());
84          setIconImage(Toolkit.getDefaultToolkit().getImage(MainFrame.class.getResource(ICON)));
85  
86          textArea = new JTextArea(20, 15);
87          textArea.setEditable(false);
88          final JScrollPane textAreaScrollPane = new JScrollPane(textArea);
89          final JPanel textAreaPanel = new JPanel();
90          textAreaPanel.setLayout(new BorderLayout());
91          textAreaPanel.add(textAreaScrollPane);
92          textAreaPanel.add(createButtonsPanel(), BorderLayout.PAGE_END);
93  
94          treeTable = new TreeTable(model.getParseTreeTableModel());
95          treeTable.setEditor(textArea);
96          treeTable.setLinePositionList(model.getLinesToPosition());
97          final JScrollPane treeTableScrollPane = new JScrollPane(treeTable);
98  
99          final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
100             treeTableScrollPane, textAreaPanel);
101 
102         add(splitPane, BorderLayout.CENTER);
103         splitPane.setResizeWeight(0.7);
104 
105         xpathTextArea = new JTextArea("Xpath", 7, 0);
106         xpathTextArea.setName("xpathTextArea");
107         xpathTextArea.setVisible(false);
108         final JPanel xpathAreaPanel = new JPanel();
109         xpathAreaPanel.setLayout(new BorderLayout());
110         xpathAreaPanel.add(xpathTextArea);
111         xpathAreaPanel.add(createXpathButtonsPanel(), BorderLayout.PAGE_END);
112 
113         treeTable.setXpathEditor(xpathTextArea);
114 
115         final Border title = BorderFactory.createTitledBorder("Xpath Query");
116         xpathAreaPanel.setBorder(title);
117 
118         add(xpathAreaPanel, BorderLayout.PAGE_END);
119     }
120 
121     /**
122      * Create buttons panel.
123      *
124      * @return buttons panel.
125      */
126     private JPanel createButtonsPanel() {
127         final JButton openFileButton = new JButton(new FileSelectionAction());
128         openFileButton.setName("openFileButton");
129         openFileButton.setMnemonic(KeyEvent.VK_O);
130         openFileButton.setText("Open File");
131 
132         reloadAction.setEnabled(false);
133         final JButton reloadFileButton = new JButton(reloadAction);
134         reloadFileButton.setMnemonic(KeyEvent.VK_R);
135         reloadFileButton.setText("Reload File");
136 
137         final JComboBox<ParseMode> modesCombobox = new JComboBox<>(ParseMode.values());
138         modesCombobox.setName("modesCombobox");
139         modesCombobox.setSelectedIndex(0);
140         modesCombobox.addActionListener(event -> {
141             model.setParseMode((ParseMode) modesCombobox.getSelectedItem());
142             reloadAction.actionPerformed(null);
143         });
144 
145         final JLabel modesLabel = new JLabel("Modes:", SwingConstants.RIGHT);
146         final int leftIndentation = 10;
147         modesLabel.setBorder(BorderFactory.createEmptyBorder(0, leftIndentation, 0, 0));
148         modesLabel.setDisplayedMnemonic(KeyEvent.VK_M);
149         modesLabel.setLabelFor(modesCombobox);
150 
151         final JPanel buttonPanel = new JPanel();
152         buttonPanel.setLayout(new GridLayout(1, 2));
153         buttonPanel.add(openFileButton);
154         buttonPanel.add(reloadFileButton);
155 
156         final JPanel modesPanel = new JPanel();
157         modesPanel.add(modesLabel);
158         modesPanel.add(modesCombobox);
159 
160         final JPanel mainPanel = new JPanel();
161         mainPanel.setLayout(new BorderLayout());
162         mainPanel.add(buttonPanel);
163         mainPanel.add(modesPanel, BorderLayout.LINE_END);
164 
165         return mainPanel;
166     }
167 
168     /**
169      * Create xpath buttons panel.
170      *
171      * @return xpath buttons panel.
172      */
173     private JPanel createXpathButtonsPanel() {
174         final JButton expandButton = new JButton(new ExpandCollapseAction());
175         expandButton.setName("expandButton");
176         expandButton.setText("Expand/Collapse");
177 
178         final JButton findNodeButton = new JButton(new FindNodeByXpathAction());
179         findNodeButton.setName("findNodeButton");
180         findNodeButton.setText("Find node by Xpath");
181 
182         final JPanel xpathButtonsPanel = new JPanel();
183         xpathButtonsPanel.setLayout(new FlowLayout());
184         xpathButtonsPanel.add(expandButton);
185         xpathButtonsPanel.add(findNodeButton);
186 
187         final JPanel mainPanel = new JPanel();
188         mainPanel.setLayout(new BorderLayout());
189         mainPanel.add(xpathButtonsPanel, BorderLayout.LINE_START);
190 
191         return mainPanel;
192     }
193 
194     /**
195      * Open file and load it.
196      *
197      * @param sourceFile the file to open.
198      */
199     public void openFile(File sourceFile) {
200         try {
201             model.openFile(sourceFile);
202             setTitle(model.getTitle());
203             reloadAction.setEnabled(model.isReloadActionEnabled());
204             textArea.setText(model.getText());
205             treeTable.setLinePositionList(model.getLinesToPosition());
206         }
207         catch (final CheckstyleException ex) {
208             JOptionPane.showMessageDialog(this, ex.getMessage());
209         }
210     }
211 
212     /**
213      * Handler for file selection action events.
214      */
215     private final class FileSelectionAction extends AbstractAction {
216 
217         /** A unique serial version identifier. */
218         private static final long serialVersionUID = 1762396148873280589L;
219 
220         @Override
221         public void actionPerformed(ActionEvent event) {
222             final JFileChooser fileChooser = new JFileChooser(model.getLastDirectory());
223             final FileFilter filter = new JavaFileFilter();
224             fileChooser.setFileFilter(filter);
225 
226             final int returnCode = fileChooser.showOpenDialog(MainFrame.this);
227             if (returnCode == JFileChooser.APPROVE_OPTION) {
228                 final File file = fileChooser.getSelectedFile();
229                 openFile(file);
230             }
231         }
232 
233     }
234 
235     /**
236      * Handler for reload action events.
237      */
238     private final class ReloadAction extends AbstractAction {
239 
240         /** A unique serial version identifier. */
241         private static final long serialVersionUID = -890320994114628011L;
242 
243         @Override
244         public void actionPerformed(ActionEvent event) {
245             openFile(model.getCurrentFile());
246         }
247 
248     }
249 
250     /**
251      * Handler for Expand and Collapse events.
252      */
253     private final class ExpandCollapseAction extends AbstractAction {
254 
255         /** A unique serial version identifier. */
256         private static final long serialVersionUID = -890320994114628011L;
257 
258         @Override
259         public void actionPerformed(ActionEvent event) {
260             xpathTextArea.setVisible(!xpathTextArea.isVisible());
261         }
262 
263     }
264 
265     /**
266      * Handler for Find Node by Xpath Event.
267      */
268     private final class FindNodeByXpathAction extends AbstractAction {
269 
270         /** A unique serial version identifier. */
271         private static final long serialVersionUID = -890320994114628011L;
272 
273         @Override
274         public void actionPerformed(ActionEvent event) {
275             treeTable.selectNodeByXpath();
276         }
277 
278     }
279 
280     /**
281      * Filter for Java files.
282      */
283     private static final class JavaFileFilter extends FileFilter {
284 
285         @Override
286         public boolean accept(File file) {
287             return MainFrameModel.shouldAcceptFile(file);
288         }
289 
290         @Override
291         public String getDescription() {
292             return "Java Source File";
293         }
294 
295     }
296 
297 }