001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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 java.awt.BorderLayout; 023import java.awt.FlowLayout; 024import java.awt.GridLayout; 025import java.awt.event.ActionEvent; 026import java.awt.event.KeyEvent; 027import java.io.File; 028 029import javax.swing.AbstractAction; 030import javax.swing.BorderFactory; 031import javax.swing.JButton; 032import javax.swing.JComboBox; 033import javax.swing.JFileChooser; 034import javax.swing.JFrame; 035import javax.swing.JLabel; 036import javax.swing.JOptionPane; 037import javax.swing.JPanel; 038import javax.swing.JScrollPane; 039import javax.swing.JSplitPane; 040import javax.swing.JTextArea; 041import javax.swing.SwingConstants; 042import javax.swing.border.Border; 043import javax.swing.filechooser.FileFilter; 044 045import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 046import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode; 047 048/** 049 * Displays information about a parse tree. 050 * The user can change the file that is parsed and displayed 051 * using a JFileChooser. 052 * 053 * @noinspection MagicNumber 054 */ 055public class MainFrame extends JFrame { 056 057 private static final long serialVersionUID = 7970053543351871890L; 058 059 /** Checkstyle frame model. */ 060 private final transient MainFrameModel model = new MainFrameModel(); 061 /** Reload action. */ 062 private final ReloadAction reloadAction = new ReloadAction(); 063 /** Code text area. */ 064 private JTextArea textArea; 065 /** Xpath text area. */ 066 private JTextArea xpathTextArea; 067 /** Tree table. */ 068 private TreeTable treeTable; 069 070 /** Create a new MainFrame. */ 071 public MainFrame() { 072 createContent(); 073 } 074 075 /** Create content of this MainFrame. */ 076 private void createContent() { 077 setLayout(new BorderLayout()); 078 079 textArea = new JTextArea(20, 15); 080 textArea.setEditable(false); 081 final JScrollPane textAreaScrollPane = new JScrollPane(textArea); 082 final JPanel textAreaPanel = new JPanel(); 083 textAreaPanel.setLayout(new BorderLayout()); 084 textAreaPanel.add(textAreaScrollPane); 085 textAreaPanel.add(createButtonsPanel(), BorderLayout.PAGE_END); 086 087 treeTable = new TreeTable(model.getParseTreeTableModel()); 088 treeTable.setEditor(textArea); 089 treeTable.setLinePositionMap(model.getLinesToPosition()); 090 final JScrollPane treeTableScrollPane = new JScrollPane(treeTable); 091 092 final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 093 treeTableScrollPane, textAreaPanel); 094 095 add(splitPane, BorderLayout.CENTER); 096 splitPane.setResizeWeight(0.7); 097 098 xpathTextArea = new JTextArea("Xpath", 7, 0); 099 xpathTextArea.setVisible(false); 100 final JPanel xpathAreaPanel = new JPanel(); 101 xpathAreaPanel.setLayout(new BorderLayout()); 102 xpathAreaPanel.add(xpathTextArea); 103 xpathAreaPanel.add(createXpathButtonsPanel(), BorderLayout.PAGE_END); 104 105 treeTable.setXpathEditor(xpathTextArea); 106 107 final Border title = BorderFactory.createTitledBorder("Xpath Query"); 108 xpathAreaPanel.setBorder(title); 109 110 add(xpathAreaPanel, BorderLayout.PAGE_END); 111 112 pack(); 113 } 114 115 /** 116 * Create buttons panel. 117 * 118 * @return buttons panel. 119 */ 120 private JPanel createButtonsPanel() { 121 final JButton openFileButton = new JButton(new FileSelectionAction()); 122 openFileButton.setMnemonic(KeyEvent.VK_S); 123 openFileButton.setText("Open File"); 124 125 reloadAction.setEnabled(false); 126 final JButton reloadFileButton = new JButton(reloadAction); 127 reloadFileButton.setMnemonic(KeyEvent.VK_R); 128 reloadFileButton.setText("Reload File"); 129 130 final JComboBox<ParseMode> modesCombobox = new JComboBox<>(ParseMode.values()); 131 modesCombobox.setSelectedIndex(0); 132 modesCombobox.addActionListener(event -> { 133 model.setParseMode((ParseMode) modesCombobox.getSelectedItem()); 134 reloadAction.actionPerformed(null); 135 }); 136 137 final JLabel modesLabel = new JLabel("Modes:", SwingConstants.RIGHT); 138 final int leftIndentation = 10; 139 modesLabel.setBorder(BorderFactory.createEmptyBorder(0, leftIndentation, 0, 0)); 140 141 final JPanel buttonPanel = new JPanel(); 142 buttonPanel.setLayout(new GridLayout(1, 2)); 143 buttonPanel.add(openFileButton); 144 buttonPanel.add(reloadFileButton); 145 146 final JPanel modesPanel = new JPanel(); 147 modesPanel.add(modesLabel); 148 modesPanel.add(modesCombobox); 149 150 final JPanel mainPanel = new JPanel(); 151 mainPanel.setLayout(new BorderLayout()); 152 mainPanel.add(buttonPanel); 153 mainPanel.add(modesPanel, BorderLayout.LINE_END); 154 155 return mainPanel; 156 } 157 158 /** 159 * Create xpath buttons panel. 160 * 161 * @return xpath buttons panel. 162 */ 163 private JPanel createXpathButtonsPanel() { 164 final JButton expandButton = new JButton(new ExpandCollapseAction()); 165 expandButton.setText("Expand/Collapse"); 166 167 final JButton findNodeButton = new JButton(); 168 findNodeButton.setText("Find node by Xpath"); 169 findNodeButton.setVisible(false); 170 171 final JPanel xpathButtonsPanel = new JPanel(); 172 xpathButtonsPanel.setLayout(new FlowLayout()); 173 xpathButtonsPanel.add(expandButton); 174 xpathButtonsPanel.add(findNodeButton); 175 176 final JPanel mainPanel = new JPanel(); 177 mainPanel.setLayout(new BorderLayout()); 178 mainPanel.add(xpathButtonsPanel, BorderLayout.LINE_START); 179 180 return mainPanel; 181 } 182 183 /** 184 * Open file and load it. 185 * 186 * @param sourceFile the file to open. 187 */ 188 public void openFile(File sourceFile) { 189 try { 190 model.openFile(sourceFile); 191 setTitle(model.getTitle()); 192 reloadAction.setEnabled(model.isReloadActionEnabled()); 193 textArea.setText(model.getText()); 194 treeTable.setLinePositionMap(model.getLinesToPosition()); 195 } 196 catch (final CheckstyleException ex) { 197 JOptionPane.showMessageDialog(this, ex.getMessage()); 198 } 199 } 200 201 /** 202 * Handler for file selection action events. 203 */ 204 private class FileSelectionAction extends AbstractAction { 205 206 private static final long serialVersionUID = 1762396148873280589L; 207 208 @Override 209 public void actionPerformed(ActionEvent event) { 210 final JFileChooser fileChooser = new JFileChooser(model.getLastDirectory()); 211 final FileFilter filter = new JavaFileFilter(); 212 fileChooser.setFileFilter(filter); 213 214 final int returnCode = fileChooser.showOpenDialog(MainFrame.this); 215 if (returnCode == JFileChooser.APPROVE_OPTION) { 216 final File file = fileChooser.getSelectedFile(); 217 openFile(file); 218 } 219 } 220 221 } 222 223 /** 224 * Handler for reload action events. 225 */ 226 private class ReloadAction extends AbstractAction { 227 228 private static final long serialVersionUID = -890320994114628011L; 229 230 @Override 231 public void actionPerformed(ActionEvent event) { 232 openFile(model.getCurrentFile()); 233 } 234 235 } 236 237 /** 238 * Handler for Expand and Collapse events. 239 */ 240 private class ExpandCollapseAction extends AbstractAction { 241 242 private static final long serialVersionUID = -890320994114628011L; 243 244 @Override 245 public void actionPerformed(ActionEvent event) { 246 xpathTextArea.setVisible(!xpathTextArea.isVisible()); 247 } 248 249 } 250 251 /** 252 * Filter for Java files. 253 */ 254 private static class JavaFileFilter extends FileFilter { 255 256 @Override 257 public boolean accept(File file) { 258 return MainFrameModel.shouldAcceptFile(file); 259 } 260 261 @Override 262 public String getDescription() { 263 return "Java Source File"; 264 } 265 266 } 267 268}