001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2018 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.GridLayout;
024import java.awt.event.ActionEvent;
025import java.awt.event.KeyEvent;
026import java.io.File;
027
028import javax.swing.AbstractAction;
029import javax.swing.BorderFactory;
030import javax.swing.JButton;
031import javax.swing.JComboBox;
032import javax.swing.JFileChooser;
033import javax.swing.JFrame;
034import javax.swing.JLabel;
035import javax.swing.JOptionPane;
036import javax.swing.JPanel;
037import javax.swing.JScrollPane;
038import javax.swing.JSplitPane;
039import javax.swing.JTextArea;
040import javax.swing.SwingConstants;
041import javax.swing.filechooser.FileFilter;
042
043import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
044import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode;
045
046/**
047 * Displays information about a parse tree.
048 * The user can change the file that is parsed and displayed
049 * using a JFileChooser.
050 *
051 * @author Lars Kühne
052 * @author Vladislav Lisetskiy
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    /** Tree table. */
066    private TreeTable treeTable;
067
068    /** Create a new MainFrame. */
069    public MainFrame() {
070        createContent();
071    }
072
073    /** Create content of this MainFrame. */
074    private void createContent() {
075        setLayout(new BorderLayout());
076
077        textArea = new JTextArea(20, 15);
078        textArea.setEditable(false);
079        final JScrollPane textAreaScrollPane = new JScrollPane(textArea);
080
081        treeTable = new TreeTable(model.getParseTreeTableModel());
082        treeTable.setEditor(textArea);
083        treeTable.setLinePositionMap(model.getLinesToPosition());
084        final JScrollPane treeTableScrollPane = new JScrollPane(treeTable);
085
086        final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, treeTableScrollPane,
087            textAreaScrollPane);
088        add(splitPane, BorderLayout.CENTER);
089        splitPane.setResizeWeight(0.7);
090
091        add(createButtonsPanel(), BorderLayout.PAGE_END);
092
093        pack();
094    }
095
096    /**
097     * Create buttons panel.
098     * @return buttons panel.
099     */
100    private JPanel createButtonsPanel() {
101        final JButton openFileButton = new JButton(new FileSelectionAction());
102        openFileButton.setMnemonic(KeyEvent.VK_S);
103        openFileButton.setText("Open File");
104
105        reloadAction.setEnabled(false);
106        final JButton reloadFileButton = new JButton(reloadAction);
107        reloadFileButton.setMnemonic(KeyEvent.VK_R);
108        reloadFileButton.setText("Reload File");
109
110        final JComboBox<ParseMode> modesCombobox = new JComboBox<>(ParseMode.values());
111        modesCombobox.setSelectedIndex(0);
112        modesCombobox.addActionListener(e -> {
113            model.setParseMode((ParseMode) modesCombobox.getSelectedItem());
114            reloadAction.actionPerformed(null);
115        });
116
117        final JLabel modesLabel = new JLabel("Modes:", SwingConstants.RIGHT);
118        final int leftIndentation = 10;
119        modesLabel.setBorder(BorderFactory.createEmptyBorder(0, leftIndentation, 0, 0));
120
121        final JPanel buttonPanel = new JPanel();
122        buttonPanel.setLayout(new GridLayout(1, 2));
123        buttonPanel.add(openFileButton);
124        buttonPanel.add(reloadFileButton);
125
126        final JPanel modesPanel = new JPanel();
127        modesPanel.add(modesLabel);
128        modesPanel.add(modesCombobox);
129
130        final JPanel mainPanel = new JPanel();
131        mainPanel.setLayout(new BorderLayout());
132        mainPanel.add(buttonPanel);
133        mainPanel.add(modesPanel, BorderLayout.LINE_END);
134
135        return mainPanel;
136    }
137
138    /**
139     * Open file and load it.
140     * @param sourceFile the file to open.
141     */
142    public void openFile(File sourceFile) {
143        try {
144            model.openFile(sourceFile);
145            setTitle(model.getTitle());
146            reloadAction.setEnabled(model.isReloadActionEnabled());
147            textArea.setText(model.getText());
148            treeTable.setLinePositionMap(model.getLinesToPosition());
149        }
150        catch (final CheckstyleException ex) {
151            JOptionPane.showMessageDialog(this, ex.getMessage());
152        }
153    }
154
155    /**
156     * Handler for file selection action events.
157     */
158    private class FileSelectionAction extends AbstractAction {
159
160        private static final long serialVersionUID = 1762396148873280589L;
161
162        @Override
163        public void actionPerformed(ActionEvent event) {
164            final JFileChooser fileChooser = new JFileChooser(model.getLastDirectory());
165            final FileFilter filter = new JavaFileFilter();
166            fileChooser.setFileFilter(filter);
167
168            final int returnCode = fileChooser.showOpenDialog(MainFrame.this);
169            if (returnCode == JFileChooser.APPROVE_OPTION) {
170                final File file = fileChooser.getSelectedFile();
171                openFile(file);
172            }
173        }
174
175    }
176
177    /**
178     * Handler for reload action events.
179     */
180    private class ReloadAction extends AbstractAction {
181
182        private static final long serialVersionUID = -890320994114628011L;
183
184        @Override
185        public void actionPerformed(ActionEvent event) {
186            openFile(model.getCurrentFile());
187        }
188
189    }
190
191    /**
192     * Filter for Java files.
193     */
194    private static class JavaFileFilter extends FileFilter {
195
196        @Override
197        public boolean accept(File file) {
198            return MainFrameModel.shouldAcceptFile(file);
199        }
200
201        @Override
202        public String getDescription() {
203            return "Java Source File";
204        }
205
206    }
207
208}