001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2019 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.io.File;
023import java.io.IOException;
024import java.nio.charset.StandardCharsets;
025import java.util.ArrayList;
026import java.util.List;
027import java.util.Locale;
028
029import com.puppycrawl.tools.checkstyle.JavaParser;
030import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
031import com.puppycrawl.tools.checkstyle.api.DetailAST;
032import com.puppycrawl.tools.checkstyle.api.FileText;
033
034/**
035 * Model for checkstyle frame.
036 */
037public class MainFrameModel {
038
039    /**
040     * Parsing modes which available in GUI.
041     */
042    public enum ParseMode {
043
044        /** Only Java tokens without comments. */
045        PLAIN_JAVA("Plain Java"),
046
047        /** Java tokens and comment nodes (singleline comments and block comments). */
048        JAVA_WITH_COMMENTS("Java with comments"),
049
050        /**
051         * Java tokens, comments and Javadoc comments nodes
052         * (which are parsed from block comments).
053         */
054        JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs");
055
056        /**
057         * Mode's short description.
058         */
059        private final String description;
060
061        /**
062         * Provides description.
063         * @param descr description
064         */
065        ParseMode(String descr) {
066            description = descr;
067        }
068
069        @Override
070        public String toString() {
071            return description;
072        }
073
074    }
075
076    /** Parse tree model. */
077    private final ParseTreeTableModel parseTreeTableModel;
078
079    /** Lines to position map. */
080    private List<Integer> linesToPosition = new ArrayList<>();
081
082    /** Current mode. */
083    private ParseMode parseMode = ParseMode.PLAIN_JAVA;
084
085    /** The file which is being parsed. */
086    private File currentFile;
087
088    /** Text for a frame's text area. */
089    private String text;
090
091    /** Title for the main frame. */
092    private String title = "Checkstyle GUI";
093
094    /** Whether the reload action is enabled. */
095    private boolean reloadActionEnabled;
096
097    /** Instantiate the model. */
098    public MainFrameModel() {
099        parseTreeTableModel = new ParseTreeTableModel(null);
100    }
101
102    /**
103     * Set current parse mode.
104     * @param mode ParseMode enum.
105     */
106    public void setParseMode(ParseMode mode) {
107        parseMode = mode;
108    }
109
110    /**
111     * Get parse tree table model.
112     * @return parse tree table model.
113     */
114    public ParseTreeTableModel getParseTreeTableModel() {
115        return parseTreeTableModel;
116    }
117
118    /**
119     * Get text to display in a text area.
120     * @return text to display in a text area.
121     */
122    public String getText() {
123        return text;
124    }
125
126    /**
127     * Returns title for the main frame.
128     * @return title for the main frame.
129     */
130    public String getTitle() {
131        return title;
132    }
133
134    /**
135     * Returns true if the reload action is enabled, false otherwise.
136     * @return true if the reload action is enabled.
137     */
138    public boolean isReloadActionEnabled() {
139        return reloadActionEnabled;
140    }
141
142    /**
143     * Whether a file chooser should accept the file as a source file.
144     * @param file the file to check.
145     * @return true if the file should be accepted.
146     */
147    public static boolean shouldAcceptFile(File file) {
148        return file.isDirectory() || file.getName().endsWith(".java");
149    }
150
151    /**
152     * Get the directory of the last loaded file.
153     * @return directory of the last loaded file.
154     */
155    public File getLastDirectory() {
156        File lastDirectory = null;
157        if (currentFile != null) {
158            lastDirectory = new File(currentFile.getParent());
159        }
160        return lastDirectory;
161    }
162
163    /**
164     * Get current file.
165     * @return current file.
166     */
167    public File getCurrentFile() {
168        return currentFile;
169    }
170
171    /**
172     * Get lines to position map.
173     * It returns unmodifiable collection to
174     * prevent additional overhead of copying
175     * and possible state modifications.
176     * @return lines to position map.
177     */
178    public List<Integer> getLinesToPosition() {
179        return new ArrayList<>(linesToPosition);
180    }
181
182    /**
183     * Open file and load the file.
184     * @param file the file to open.
185     * @throws CheckstyleException if the file can not be parsed.
186     */
187    public void openFile(File file) throws CheckstyleException {
188        if (file != null) {
189            try {
190                currentFile = file;
191                title = "Checkstyle GUI : " + file.getName();
192                reloadActionEnabled = true;
193                final DetailAST parseTree;
194
195                switch (parseMode) {
196                    case PLAIN_JAVA:
197                        parseTree = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS);
198                        break;
199                    case JAVA_WITH_COMMENTS:
200                    case JAVA_WITH_JAVADOC_AND_COMMENTS:
201                        parseTree = JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS);
202                        break;
203                    default:
204                        throw new IllegalArgumentException("Unknown mode: " + parseMode);
205                }
206
207                parseTreeTableModel.setParseTree(parseTree);
208                parseTreeTableModel.setParseMode(parseMode);
209                final String[] sourceLines = getFileText(file).toLinesArray();
210
211                final List<Integer> linesToPositionTemp = new ArrayList<>();
212                // starts line counting at 1
213                linesToPositionTemp.add(0);
214
215                final StringBuilder sb = new StringBuilder(1024);
216                // insert the contents of the file to the text area
217                for (final String element : sourceLines) {
218                    linesToPositionTemp.add(sb.length());
219                    sb.append(element).append(System.lineSeparator());
220                }
221                linesToPosition = linesToPositionTemp;
222                text = sb.toString();
223            }
224            catch (IOException ex) {
225                final String exceptionMsg = String.format(Locale.ROOT,
226                    "%s occurred while opening file %s.",
227                    ex.getClass().getSimpleName(), file.getPath());
228                throw new CheckstyleException(exceptionMsg, ex);
229            }
230        }
231    }
232
233    /**
234     * Get FileText from a file.
235     * @param file the file to get the FileText from.
236     * @return the FileText.
237     * @throws IOException if the file could not be read.
238     */
239    private static FileText getFileText(File file) throws IOException {
240        return new FileText(file.getAbsoluteFile(),
241                System.getProperty("file.encoding", StandardCharsets.UTF_8.name()));
242    }
243
244}