View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.gui;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.nio.charset.StandardCharsets;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Locale;
28  
29  import antlr.ANTLRException;
30  import com.google.common.collect.ImmutableList;
31  import com.puppycrawl.tools.checkstyle.TreeWalker;
32  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
33  import com.puppycrawl.tools.checkstyle.api.DetailAST;
34  import com.puppycrawl.tools.checkstyle.api.FileContents;
35  import com.puppycrawl.tools.checkstyle.api.FileText;
36  
37  /**
38   * Model for checkstyle frame.
39   * @author Vladislav Lisetskiy
40   */
41  public class MainFrameModel {
42  
43      /**
44       * Parsing modes which available in GUI.
45       */
46      public enum ParseMode {
47  
48          /** Only Java tokens without comments. */
49          PLAIN_JAVA("Plain Java"),
50  
51          /** Java tokens and comment nodes (singleline comments and block comments). */
52          JAVA_WITH_COMMENTS("Java with comments"),
53  
54          /**
55           * Java tokens, comments and Javadoc comments nodes
56           * (which are parsed from block comments).
57           */
58          JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs");
59  
60          /**
61           * Mode's short description.
62           */
63          private final String description;
64  
65          /**
66           * Provides description.
67           * @param descr description
68           */
69          ParseMode(String descr) {
70              description = descr;
71          }
72  
73          @Override
74          public String toString() {
75              return description;
76          }
77      }
78  
79      /** Parse tree model. */
80      private final ParseTreeTableModel parseTreeTableModel;
81  
82      /** Lines to position map. */
83      private ImmutableList<Integer> linesToPosition = ImmutableList.of();
84  
85      /** Current mode. */
86      private ParseMode parseMode = ParseMode.PLAIN_JAVA;
87  
88      /** The file which is being parsed. */
89      private File currentFile;
90  
91      /** Text for a frame's text area. */
92      private String text;
93  
94      /** Title for the main frame. */
95      private String title = "Checkstyle GUI";
96  
97      /** Whether the reload action is enabled. */
98      private boolean reloadActionEnabled;
99  
100     /** Instantiate the model. */
101     public MainFrameModel() {
102         parseTreeTableModel = new ParseTreeTableModel(null);
103     }
104 
105     /**
106      * Set current parse mode.
107      * @param mode ParseMode enum.
108      */
109     public void setParseMode(ParseMode mode) {
110         parseMode = mode;
111     }
112 
113     /**
114      * Get parse tree table model.
115      * @return parse tree table model.
116      */
117     public ParseTreeTableModel getParseTreeTableModel() {
118         return parseTreeTableModel;
119     }
120 
121     /**
122      * Get text to display in a text area.
123      * @return text to display in a text area.
124      */
125     public String getText() {
126         return text;
127     }
128 
129     /**
130      * Returns title for the main frame.
131      * @return title for the main frame.
132      */
133     public String getTitle() {
134         return title;
135     }
136 
137     /**
138      * Returns true if the reload action is enabled, false otherwise.
139      * @return true if the reload action is enabled.
140      */
141     public boolean isReloadActionEnabled() {
142         return reloadActionEnabled;
143     }
144 
145     /**
146      * Whether a file chooser should accept the file as a source file.
147      * @param file the file to check.
148      * @return true if the file should be accepted.
149      */
150     public static boolean shouldAcceptFile(File file) {
151         return file.isDirectory() || file.getName().endsWith(".java");
152     }
153 
154     /**
155      * Get the directory of the last loaded file.
156      * @return directory of the last loaded file.
157      */
158     public File getLastDirectory() {
159         File lastDirectory = null;
160         if (currentFile != null) {
161             lastDirectory = new File(currentFile.getParent());
162         }
163         return lastDirectory;
164     }
165 
166     /**
167      * Get current file.
168      * @return current file.
169      */
170     public File getCurrentFile() {
171         return currentFile;
172     }
173 
174     /**
175      * Get lines to position map.
176      * It returns unmodifiable collection to
177      * prevent additional overhead of copying
178      * and possible state modifications.
179      * @return lines to position map.
180      * @noinspection ReturnOfCollectionOrArrayField
181      */
182     public ImmutableList<Integer> getLinesToPosition() {
183         return linesToPosition;
184     }
185 
186     /**
187      * Open file and load the file.
188      * @param file the file to open.
189      * @throws CheckstyleException if the file can not be parsed.
190      */
191     public void openFile(File file) throws CheckstyleException {
192         if (file != null) {
193             try {
194                 currentFile = file;
195                 title = "Checkstyle GUI : " + file.getName();
196                 reloadActionEnabled = true;
197                 final DetailAST parseTree;
198 
199                 switch (parseMode) {
200                     case PLAIN_JAVA:
201                         parseTree = parseFile(file);
202                         break;
203                     case JAVA_WITH_COMMENTS:
204                     case JAVA_WITH_JAVADOC_AND_COMMENTS:
205                         parseTree = parseFileWithComments(file);
206                         break;
207                     default:
208                         throw new IllegalArgumentException("Unknown mode: " + parseMode);
209                 }
210 
211                 parseTreeTableModel.setParseTree(parseTree);
212                 parseTreeTableModel.setParseMode(parseMode);
213                 final String[] sourceLines = getFileText(file).toLinesArray();
214 
215                 final List<Integer> linesToPositionTemp = new ArrayList<>();
216                 // starts line counting at 1
217                 linesToPositionTemp.add(0);
218 
219                 final StringBuilder sb = new StringBuilder(1024);
220                 // insert the contents of the file to the text area
221                 for (final String element : sourceLines) {
222                     linesToPositionTemp.add(sb.length());
223                     sb.append(element).append(System.lineSeparator());
224                 }
225                 linesToPosition = ImmutableList.copyOf(linesToPositionTemp);
226                 text = sb.toString();
227             }
228             catch (IOException | ANTLRException ex) {
229                 final String exceptionMsg = String.format(Locale.ROOT,
230                     "%s occurred while opening file %s.",
231                     ex.getClass().getSimpleName(), file.getPath());
232                 throw new CheckstyleException(exceptionMsg, ex);
233             }
234         }
235     }
236 
237     /**
238      * Parse a file and return the parse tree.
239      * @param file the file to parse.
240      * @return the root node of the parse tree.
241      * @throws IOException if the file could not be read.
242      * @throws ANTLRException if the file is not a Java source.
243      */
244     private static DetailAST parseFile(File file) throws IOException, ANTLRException {
245         final FileText fileText = getFileText(file);
246         final FileContents contents = new FileContents(fileText);
247         return TreeWalker.parse(contents);
248     }
249 
250     /**
251      * Parse a file and return the parse tree with comment nodes.
252      * @param file the file to parse.
253      * @return the root node of the parse tree.
254      * @throws IOException if the file could not be read.
255      * @throws ANTLRException if the file is not a Java source.
256      */
257     private static DetailAST parseFileWithComments(File file) throws IOException, ANTLRException {
258         final FileText fileText = getFileText(file);
259         final FileContents contents = new FileContents(fileText);
260         return TreeWalker.parseWithComments(contents);
261     }
262 
263     /**
264      * Get FileText from a file.
265      * @param file the file to get the FileText from.
266      * @return the FileText.
267      * @throws IOException if the file could not be read.
268      */
269     private static FileText getFileText(File file) throws IOException {
270         return new FileText(file.getAbsoluteFile(),
271                 System.getProperty("file.encoding", StandardCharsets.UTF_8.name()));
272     }
273 }