001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 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.puppycrawl.tools.checkstyle.JavaParser; 030import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 031import com.puppycrawl.tools.checkstyle.api.DetailAST; 032import com.puppycrawl.tools.checkstyle.api.FileText; 033 034/** 035 * Model for checkstyle frame. 036 */ 037public class MainFrameModel { 038 039 /** 040 * Parsing modes which available in GUI. 041 */ 042 public enum ParseMode { 043 044 /** Only Java tokens without comments. */ 045 PLAIN_JAVA("Plain Java"), 046 047 /** Java tokens and comment nodes (singleline comments and block comments). */ 048 JAVA_WITH_COMMENTS("Java with comments"), 049 050 /** 051 * Java tokens, comments and Javadoc comments nodes 052 * (which are parsed from block comments). 053 */ 054 JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs"); 055 056 /** 057 * Mode's short description. 058 */ 059 private final String description; 060 061 /** 062 * Provides description. 063 * 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 List<Integer> linesToPosition = new ArrayList<>(); 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 * 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 * 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 * 124 * @return text to display in a text area. 125 */ 126 public String getText() { 127 return text; 128 } 129 130 /** 131 * Returns title for the main frame. 132 * 133 * @return title for the main frame. 134 */ 135 public String getTitle() { 136 return title; 137 } 138 139 /** 140 * Returns true if the reload action is enabled, false otherwise. 141 * 142 * @return true if the reload action is enabled. 143 */ 144 public boolean isReloadActionEnabled() { 145 return reloadActionEnabled; 146 } 147 148 /** 149 * Whether a file chooser should accept the file as a source file. 150 * 151 * @param file the file to check. 152 * @return true if the file should be accepted. 153 */ 154 public static boolean shouldAcceptFile(File file) { 155 return file.isDirectory() || file.getName().endsWith(".java"); 156 } 157 158 /** 159 * Get the directory of the last loaded file. 160 * 161 * @return directory of the last loaded file. 162 */ 163 public File getLastDirectory() { 164 File lastDirectory = null; 165 if (currentFile != null) { 166 lastDirectory = currentFile.getParentFile(); 167 } 168 return lastDirectory; 169 } 170 171 /** 172 * Get current file. 173 * 174 * @return current file. 175 */ 176 public File getCurrentFile() { 177 return currentFile; 178 } 179 180 /** 181 * Get lines to position map. 182 * It returns unmodifiable collection to 183 * prevent additional overhead of copying 184 * and possible state modifications. 185 * 186 * @return lines to position map. 187 */ 188 public List<Integer> getLinesToPosition() { 189 return new ArrayList<>(linesToPosition); 190 } 191 192 /** 193 * Open file and load the file. 194 * 195 * @param file the file to open. 196 * @throws CheckstyleException if the file can not be parsed. 197 * @throws IllegalArgumentException if parseMode is unknown 198 */ 199 public void openFile(File file) throws CheckstyleException { 200 if (file != null) { 201 try { 202 currentFile = file; 203 title = "Checkstyle GUI : " + file.getName(); 204 reloadActionEnabled = true; 205 final DetailAST parseTree; 206 207 if (parseMode == ParseMode.PLAIN_JAVA) { 208 parseTree = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS); 209 } 210 else if (parseMode == ParseMode.JAVA_WITH_COMMENTS 211 || parseMode == ParseMode.JAVA_WITH_JAVADOC_AND_COMMENTS) { 212 parseTree = JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS); 213 } 214 else { 215 throw new IllegalArgumentException("Unknown mode: " + parseMode); 216 } 217 218 parseTreeTableModel.setParseTree(parseTree); 219 parseTreeTableModel.setParseMode(parseMode); 220 final String[] sourceLines = getFileText(file).toLinesArray(); 221 222 final List<Integer> linesToPositionTemp = new ArrayList<>(sourceLines.length + 1); 223 // starts line counting at 1 224 linesToPositionTemp.add(0); 225 226 final StringBuilder sb = new StringBuilder(1024); 227 // insert the contents of the file to the text area 228 for (final String element : sourceLines) { 229 linesToPositionTemp.add(sb.length()); 230 sb.append(element).append(System.lineSeparator()); 231 } 232 linesToPosition = linesToPositionTemp; 233 text = sb.toString(); 234 } 235 catch (IOException ex) { 236 final String exceptionMsg = String.format(Locale.ROOT, 237 "%s occurred while opening file %s.", 238 ex.getClass().getSimpleName(), file.getPath()); 239 throw new CheckstyleException(exceptionMsg, ex); 240 } 241 } 242 } 243 244 /** 245 * Get FileText from a file. 246 * 247 * @param file the file to get the FileText from. 248 * @return the FileText. 249 * @throws IOException if the file could not be read. 250 */ 251 private static FileText getFileText(File file) throws IOException { 252 return new FileText(file.getAbsoluteFile(), 253 System.getProperty("file.encoding", StandardCharsets.UTF_8.name())); 254 } 255 256}