blob: cf7d881f7ed5bf438f61ca05cbab7697f437b602 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2017 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.gui;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import antlr.ANTLRException;
import com.google.common.collect.ImmutableList;
import com.puppycrawl.tools.checkstyle.TreeWalker;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FileContents;
import com.puppycrawl.tools.checkstyle.api.FileText;
/**
* Model for checkstyle frame.
* @author Vladislav Lisetskiy
*/
public class MainFrameModel {
/**
* Parsing modes which available in GUI.
*/
public enum ParseMode {
/** Only Java tokens without comments. */
PLAIN_JAVA("Plain Java"),
/** Java tokens and comment nodes (singleline comments and block comments). */
JAVA_WITH_COMMENTS("Java with comments"),
/**
* Java tokens, comments and Javadoc comments nodes
* (which are parsed from block comments).
*/
JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs");
/**
* Mode's short description.
*/
private final String description;
/**
* Provides description.
* @param descr description
*/
ParseMode(String descr) {
description = descr;
}
@Override
public String toString() {
return description;
}
}
/** Parse tree model. */
private final ParseTreeTableModel parseTreeTableModel;
/** Lines to position map. */
private ImmutableList<Integer> linesToPosition = ImmutableList.of();
/** Current mode. */
private ParseMode parseMode = ParseMode.PLAIN_JAVA;
/** The file which is being parsed. */
private File currentFile;
/** Text for a frame's text area. */
private String text;
/** Title for the main frame. */
private String title = "Checkstyle GUI";
/** Whether the reload action is enabled. */
private boolean reloadActionEnabled;
/** Instantiate the model. */
public MainFrameModel() {
parseTreeTableModel = new ParseTreeTableModel(null);
}
/**
* Set current parse mode.
* @param mode ParseMode enum.
*/
public void setParseMode(ParseMode mode) {
parseMode = mode;
}
/**
* Get parse tree table model.
* @return parse tree table model.
*/
public ParseTreeTableModel getParseTreeTableModel() {
return parseTreeTableModel;
}
/**
* Get text to display in a text area.
* @return text to display in a text area.
*/
public String getText() {
return text;
}
/**
* Returns title for the main frame.
* @return title for the main frame.
*/
public String getTitle() {
return title;
}
/**
* Returns true if the reload action is enabled, false otherwise.
* @return true if the reload action is enabled.
*/
public boolean isReloadActionEnabled() {
return reloadActionEnabled;
}
/**
* Whether a file chooser should accept the file as a source file.
* @param file the file to check.
* @return true if the file should be accepted.
*/
public static boolean shouldAcceptFile(File file) {
return file.isDirectory() || file.getName().endsWith(".java");
}
/**
* Get the directory of the last loaded file.
* @return directory of the last loaded file.
*/
public File getLastDirectory() {
File lastDirectory = null;
if (currentFile != null) {
lastDirectory = new File(currentFile.getParent());
}
return lastDirectory;
}
/**
* Get current file.
* @return current file.
*/
public File getCurrentFile() {
return currentFile;
}
/**
* Get lines to position map.
* It returns unmodifiable collection to
* prevent additional overhead of copying
* and possible state modifications.
* @return lines to position map.
* @noinspection ReturnOfCollectionOrArrayField
*/
public ImmutableList<Integer> getLinesToPosition() {
return linesToPosition;
}
/**
* Open file and load the file.
* @param file the file to open.
* @throws CheckstyleException if the file can not be parsed.
*/
public void openFile(File file) throws CheckstyleException {
if (file != null) {
try {
currentFile = file;
title = "Checkstyle GUI : " + file.getName();
reloadActionEnabled = true;
final DetailAST parseTree;
switch (parseMode) {
case PLAIN_JAVA:
parseTree = parseFile(file);
break;
case JAVA_WITH_COMMENTS:
case JAVA_WITH_JAVADOC_AND_COMMENTS:
parseTree = parseFileWithComments(file);
break;
default:
throw new IllegalArgumentException("Unknown mode: " + parseMode);
}
parseTreeTableModel.setParseTree(parseTree);
parseTreeTableModel.setParseMode(parseMode);
final String[] sourceLines = getFileText(file).toLinesArray();
final List<Integer> linesToPositionTemp = new ArrayList<>();
// starts line counting at 1
linesToPositionTemp.add(0);
final StringBuilder sb = new StringBuilder(1024);
// insert the contents of the file to the text area
for (final String element : sourceLines) {
linesToPositionTemp.add(sb.length());
sb.append(element).append(System.lineSeparator());
}
linesToPosition = ImmutableList.copyOf(linesToPositionTemp);
text = sb.toString();
}
catch (IOException | ANTLRException ex) {
final String exceptionMsg = String.format(Locale.ROOT,
"%s occurred while opening file %s.",
ex.getClass().getSimpleName(), file.getPath());
throw new CheckstyleException(exceptionMsg, ex);
}
}
}
/**
* Parse a file and return the parse tree.
* @param file the file to parse.
* @return the root node of the parse tree.
* @throws IOException if the file could not be read.
* @throws ANTLRException if the file is not a Java source.
*/
private static DetailAST parseFile(File file) throws IOException, ANTLRException {
final FileText fileText = getFileText(file);
final FileContents contents = new FileContents(fileText);
return TreeWalker.parse(contents);
}
/**
* Parse a file and return the parse tree with comment nodes.
* @param file the file to parse.
* @return the root node of the parse tree.
* @throws IOException if the file could not be read.
* @throws ANTLRException if the file is not a Java source.
*/
private static DetailAST parseFileWithComments(File file) throws IOException, ANTLRException {
final FileText fileText = getFileText(file);
final FileContents contents = new FileContents(fileText);
return TreeWalker.parseWithComments(contents);
}
/**
* Get FileText from a file.
* @param file the file to get the FileText from.
* @return the FileText.
* @throws IOException if the file could not be read.
*/
private static FileText getFileText(File file) throws IOException {
return new FileText(file.getAbsoluteFile(),
System.getProperty("file.encoding", StandardCharsets.UTF_8.name()));
}
}