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