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 * @return title for the main frame. 130 */ 131 public String getTitle() { 132 return title; 133 } 134 135 /** 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 * @return lines to position map. 174 */ 175 public List<Integer> getLinesToPosition() { 176 final List<Integer> copy = new ArrayList<>(linesToPosition); 177 return Collections.unmodifiableList(copy); 178 } 179 180 /** 181 * Open file and load the file. 182 * @param file the file to open. 183 * @throws CheckstyleException if the file can not be parsed. 184 */ 185 public void openFile(File file) throws CheckstyleException { 186 if (file != null) { 187 try { 188 currentFile = file; 189 title = "Checkstyle GUI : " + file.getName(); 190 reloadActionEnabled = true; 191 final DetailAST parseTree; 192 193 switch (parseMode) { 194 case PLAIN_JAVA: 195 parseTree = parseFile(file); 196 break; 197 case JAVA_WITH_COMMENTS: 198 case JAVA_WITH_JAVADOC_AND_COMMENTS: 199 parseTree = parseFileWithComments(file); 200 break; 201 default: 202 throw new IllegalArgumentException("Unknown mode: " + parseMode); 203 } 204 205 parseTreeTableModel.setParseTree(parseTree); 206 parseTreeTableModel.setParseMode(parseMode); 207 final String[] sourceLines = getFileText(file).toLinesArray(); 208 209 // clear for each new file 210 linesToPosition.clear(); 211 // starts line counting at 1 212 linesToPosition.add(0); 213 214 final StringBuilder sb = new StringBuilder(); 215 // insert the contents of the file to the text area 216 for (final String element : sourceLines) { 217 linesToPosition.add(sb.length()); 218 sb.append(element).append(System.lineSeparator()); 219 } 220 text = sb.toString(); 221 } 222 catch (IOException | ANTLRException ex) { 223 final String exceptionMsg = String.format(Locale.ROOT, 224 "%s occurred while opening file %s.", 225 ex.getClass().getSimpleName(), file.getPath()); 226 throw new CheckstyleException(exceptionMsg, ex); 227 } 228 } 229 } 230 231 /** 232 * Parse a file and return the parse tree. 233 * @param file the file to parse. 234 * @return the root node of the parse tree. 235 * @throws IOException if the file could not be read. 236 * @throws ANTLRException if the file is not a Java source. 237 */ 238 public DetailAST parseFile(File file) throws IOException, ANTLRException { 239 final FileText fileText = getFileText(file); 240 final FileContents contents = new FileContents(fileText); 241 return TreeWalker.parse(contents); 242 } 243 244 /** 245 * Parse a file and return the parse tree with comment nodes. 246 * @param file the file to parse. 247 * @return the root node of the parse tree. 248 * @throws IOException if the file could not be read. 249 * @throws ANTLRException if the file is not a Java source. 250 */ 251 public DetailAST parseFileWithComments(File file) throws IOException, ANTLRException { 252 final FileText fileText = getFileText(file); 253 final FileContents contents = new FileContents(fileText); 254 return TreeWalker.parseWithComments(contents); 255 } 256 257 /** 258 * Get FileText from a file. 259 * @param file the file to get the FileText from. 260 * @return the FileText. 261 * @throws IOException if the file could not be read. 262 */ 263 public FileText getFileText(File file) throws IOException { 264 return new FileText(file.getAbsoluteFile(), 265 System.getProperty("file.encoding", "UTF-8")); 266 } 267}