1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2025 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.gui;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.nio.charset.StandardCharsets;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Locale;
28
29 import com.puppycrawl.tools.checkstyle.JavaParser;
30 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
31 import com.puppycrawl.tools.checkstyle.api.DetailAST;
32 import com.puppycrawl.tools.checkstyle.api.FileText;
33
34 /**
35 * Model for checkstyle frame.
36 */
37 public class MainFrameModel {
38
39 /**
40 * Parsing modes which available in GUI.
41 */
42 public enum ParseMode {
43
44 /** Only Java tokens without comments. */
45 PLAIN_JAVA("Plain Java"),
46
47 /** Java tokens and comment nodes (singleline comments and block comments). */
48 JAVA_WITH_COMMENTS("Java with comments"),
49
50 /**
51 * Java tokens, comments and Javadoc comments nodes
52 * (which are parsed from block comments).
53 */
54 JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs");
55
56 /**
57 * Mode's short description.
58 */
59 private final String description;
60
61 /**
62 * Provides description.
63 *
64 * @param descr description
65 */
66 ParseMode(String descr) {
67 description = descr;
68 }
69
70 @Override
71 public String toString() {
72 return description;
73 }
74
75 }
76
77 /** Parse tree model. */
78 private final ParseTreeTableModel parseTreeTableModel;
79
80 /** Lines to position map. */
81 private List<Integer> linesToPosition = new ArrayList<>();
82
83 /** Current mode. */
84 private ParseMode parseMode = ParseMode.PLAIN_JAVA;
85
86 /** The file which is being parsed. */
87 private File currentFile;
88
89 /** Text for a frame's text area. */
90 private String text;
91
92 /** Title for the main frame. */
93 private String title = "Checkstyle GUI";
94
95 /** Whether the reload action is enabled. */
96 private boolean reloadActionEnabled;
97
98 /** Instantiate the model. */
99 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 exc) {
236 final String exceptionMsg = String.format(Locale.ROOT,
237 "%s occurred while opening file %s.",
238 exc.getClass().getSimpleName(), file.getPath());
239 throw new CheckstyleException(exceptionMsg, exc);
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 }