001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2018 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.google.common.collect.ImmutableList; 030import com.puppycrawl.tools.checkstyle.JavaParser; 031import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 032import com.puppycrawl.tools.checkstyle.api.DetailAST; 033import com.puppycrawl.tools.checkstyle.api.FileText; 034 035/** 036 * Model for checkstyle frame. 037 * @author Vladislav Lisetskiy 038 */ 039public class MainFrameModel { 040 041 /** 042 * Parsing modes which available in GUI. 043 */ 044 public enum ParseMode { 045 046 /** Only Java tokens without comments. */ 047 PLAIN_JAVA("Plain Java"), 048 049 /** Java tokens and comment nodes (singleline comments and block comments). */ 050 JAVA_WITH_COMMENTS("Java with comments"), 051 052 /** 053 * Java tokens, comments and Javadoc comments nodes 054 * (which are parsed from block comments). 055 */ 056 JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs"); 057 058 /** 059 * Mode's short description. 060 */ 061 private final String description; 062 063 /** 064 * Provides description. 065 * @param descr description 066 */ 067 ParseMode(String descr) { 068 description = descr; 069 } 070 071 @Override 072 public String toString() { 073 return description; 074 } 075 076 } 077 078 /** Parse tree model. */ 079 private final ParseTreeTableModel parseTreeTableModel; 080 081 /** Lines to position map. */ 082 private ImmutableList<Integer> linesToPosition = ImmutableList.of(); 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 * It returns unmodifiable collection to 176 * prevent additional overhead of copying 177 * and possible state modifications. 178 * @return lines to position map. 179 * @noinspection ReturnOfCollectionOrArrayField 180 */ 181 public ImmutableList<Integer> getLinesToPosition() { 182 return linesToPosition; 183 } 184 185 /** 186 * Open file and load the file. 187 * @param file the file to open. 188 * @throws CheckstyleException if the file can not be parsed. 189 */ 190 public void openFile(File file) throws CheckstyleException { 191 if (file != null) { 192 try { 193 currentFile = file; 194 title = "Checkstyle GUI : " + file.getName(); 195 reloadActionEnabled = true; 196 final DetailAST parseTree; 197 198 switch (parseMode) { 199 case PLAIN_JAVA: 200 parseTree = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS); 201 break; 202 case JAVA_WITH_COMMENTS: 203 case JAVA_WITH_JAVADOC_AND_COMMENTS: 204 parseTree = JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS); 205 break; 206 default: 207 throw new IllegalArgumentException("Unknown mode: " + parseMode); 208 } 209 210 parseTreeTableModel.setParseTree(parseTree); 211 parseTreeTableModel.setParseMode(parseMode); 212 final String[] sourceLines = getFileText(file).toLinesArray(); 213 214 final List<Integer> linesToPositionTemp = new ArrayList<>(); 215 // starts line counting at 1 216 linesToPositionTemp.add(0); 217 218 final StringBuilder sb = new StringBuilder(1024); 219 // insert the contents of the file to the text area 220 for (final String element : sourceLines) { 221 linesToPositionTemp.add(sb.length()); 222 sb.append(element).append(System.lineSeparator()); 223 } 224 linesToPosition = ImmutableList.copyOf(linesToPositionTemp); 225 text = sb.toString(); 226 } 227 catch (IOException ex) { 228 final String exceptionMsg = String.format(Locale.ROOT, 229 "%s occurred while opening file %s.", 230 ex.getClass().getSimpleName(), file.getPath()); 231 throw new CheckstyleException(exceptionMsg, ex); 232 } 233 } 234 } 235 236 /** 237 * Get FileText from a file. 238 * @param file the file to get the FileText from. 239 * @return the FileText. 240 * @throws IOException if the file could not be read. 241 */ 242 private static FileText getFileText(File file) throws IOException { 243 return new FileText(file.getAbsoluteFile(), 244 System.getProperty("file.encoding", StandardCharsets.UTF_8.name())); 245 } 246 247}