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