001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2017 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.util.ArrayList; 025import java.util.Collections; 026import java.util.List; 027import java.util.Locale; 028 029import antlr.ANTLRException; 030import com.puppycrawl.tools.checkstyle.TreeWalker; 031import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 032import com.puppycrawl.tools.checkstyle.api.DetailAST; 033import com.puppycrawl.tools.checkstyle.api.FileContents; 034import com.puppycrawl.tools.checkstyle.api.FileText; 035 036/** 037 * Model for checkstyle frame. 038 * @author Vladislav Lisetskiy 039 */ 040public class MainFrameModel { 041 042 /** 043 * Parsing modes which available in GUI. 044 */ 045 public enum ParseMode { 046 047 /** Only Java tokens without comments. */ 048 PLAIN_JAVA("Plain Java"), 049 050 /** Java tokens and comment nodes (singleline comments and block comments). */ 051 JAVA_WITH_COMMENTS("Java with comments"), 052 053 /** 054 * Java tokens, comments and Javadoc comments nodes 055 * (which are parsed from block comments). 056 */ 057 JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs"); 058 059 /** 060 * Mode's short description. 061 */ 062 private final String description; 063 064 /** 065 * Provides description. 066 * @param descr description 067 */ 068 ParseMode(String descr) { 069 description = descr; 070 } 071 072 @Override 073 public String toString() { 074 return description; 075 } 076 } 077 078 /** Lines to position map. */ 079 private final List<Integer> linesToPosition = new ArrayList<>(); 080 081 /** Parse tree model. */ 082 private final ParseTreeTableModel parseTreeTableModel; 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 * @return lines to position map. 176 */ 177 public List<Integer> getLinesToPosition() { 178 final List<Integer> copy = new ArrayList<>(linesToPosition); 179 return Collections.unmodifiableList(copy); 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 = parseFile(file); 198 break; 199 case JAVA_WITH_COMMENTS: 200 case JAVA_WITH_JAVADOC_AND_COMMENTS: 201 parseTree = parseFileWithComments(file); 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 // clear for each new file 212 linesToPosition.clear(); 213 // starts line counting at 1 214 linesToPosition.add(0); 215 216 final StringBuilder sb = new StringBuilder(); 217 // insert the contents of the file to the text area 218 for (final String element : sourceLines) { 219 linesToPosition.add(sb.length()); 220 sb.append(element).append(System.lineSeparator()); 221 } 222 text = sb.toString(); 223 } 224 catch (IOException | ANTLRException 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 * Parse a file and return the parse tree. 235 * @param file the file to parse. 236 * @return the root node of the parse tree. 237 * @throws IOException if the file could not be read. 238 * @throws ANTLRException if the file is not a Java source. 239 */ 240 public DetailAST parseFile(File file) throws IOException, ANTLRException { 241 final FileText fileText = getFileText(file); 242 final FileContents contents = new FileContents(fileText); 243 return TreeWalker.parse(contents); 244 } 245 246 /** 247 * Parse a file and return the parse tree with comment nodes. 248 * @param file the file to parse. 249 * @return the root node of the parse tree. 250 * @throws IOException if the file could not be read. 251 * @throws ANTLRException if the file is not a Java source. 252 */ 253 public DetailAST parseFileWithComments(File file) throws IOException, ANTLRException { 254 final FileText fileText = getFileText(file); 255 final FileContents contents = new FileContents(fileText); 256 return TreeWalker.parseWithComments(contents); 257 } 258 259 /** 260 * Get FileText from a file. 261 * @param file the file to get the FileText from. 262 * @return the FileText. 263 * @throws IOException if the file could not be read. 264 */ 265 public FileText getFileText(File file) throws IOException { 266 return new FileText(file.getAbsoluteFile(), 267 System.getProperty("file.encoding", "UTF-8")); 268 } 269}