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