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