001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2024 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.util.List;
023
024import com.puppycrawl.tools.checkstyle.api.DetailAST;
025import com.puppycrawl.tools.checkstyle.api.DetailNode;
026import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
027
028/**
029 * Presentation model for CodeSelector.
030 */
031public class CodeSelectorPresentation {
032
033    /** DetailAST or DetailNode node. */
034    private final Object node;
035    /** Mapping. */
036    private final List<Integer> lines2position;
037    /** Selection start position. */
038    private int selectionStart;
039    /** Selection end position. */
040    private int selectionEnd;
041
042    /**
043     * Constructor.
044     *
045     * @param ast ast node.
046     * @param lines2position positions of lines.
047     * @noinspection AssignmentOrReturnOfFieldWithMutableType
048     * @noinspectionreason AssignmentOrReturnOfFieldWithMutableType - mutability is
049     *      expected in list of lines of code
050     */
051    public CodeSelectorPresentation(DetailAST ast, List<Integer> lines2position) {
052        node = ast;
053        this.lines2position = lines2position;
054    }
055
056    /**
057     * Constructor.
058     *
059     * @param node DetailNode node.
060     * @param lines2position list to map lines.
061     * @noinspection AssignmentOrReturnOfFieldWithMutableType
062     * @noinspectionreason AssignmentOrReturnOfFieldWithMutableType - mutability is expected
063     *      in list of lines of code
064     */
065    public CodeSelectorPresentation(DetailNode node, List<Integer> lines2position) {
066        this.node = node;
067        this.lines2position = lines2position;
068    }
069
070    /**
071     * Returns selection start position.
072     *
073     * @return selection start position.
074     */
075    public int getSelectionStart() {
076        return selectionStart;
077    }
078
079    /**
080     * Returns selection end position.
081     *
082     * @return selection end position.
083     */
084    public int getSelectionEnd() {
085        return selectionEnd;
086    }
087
088    /**
089     * Find start and end selection positions from AST line and Column.
090     */
091    public void findSelectionPositions() {
092        if (node instanceof DetailAST) {
093            findSelectionPositions((DetailAST) node);
094        }
095        else {
096            findSelectionPositions((DetailNode) node);
097        }
098    }
099
100    /**
101     * Find start and end selection positions from AST line and Column.
102     *
103     * @param ast DetailAST node for which selection finds
104     */
105    private void findSelectionPositions(DetailAST ast) {
106        selectionStart = lines2position.get(ast.getLineNo()) + ast.getColumnNo();
107
108        if (ast.hasChildren() || !TokenUtil.getTokenName(ast.getType()).equals(ast.getText())) {
109            selectionEnd = findLastPosition(ast);
110        }
111        else {
112            selectionEnd = selectionStart;
113        }
114    }
115
116    /**
117     * Find start and end selection positions from DetailNode line and Column.
118     *
119     * @param detailNode DetailNode node for which selection finds
120     */
121    private void findSelectionPositions(DetailNode detailNode) {
122        selectionStart = lines2position.get(detailNode.getLineNumber())
123                            + detailNode.getColumnNumber();
124
125        selectionEnd = findLastPosition(detailNode);
126    }
127
128    /**
129     * Finds the last position of node without children.
130     *
131     * @param astNode DetailAST node.
132     * @return Last position of node without children.
133     */
134    private int findLastPosition(final DetailAST astNode) {
135        final int lastPosition;
136        if (astNode.hasChildren()) {
137            lastPosition = findLastPosition(astNode.getLastChild());
138        }
139        else {
140            lastPosition = lines2position.get(astNode.getLineNo()) + astNode.getColumnNo()
141                    + astNode.getText().length();
142        }
143        return lastPosition;
144    }
145
146    /**
147     * Finds the last position of node without children.
148     *
149     * @param detailNode DetailNode node.
150     * @return Last position of node without children.
151     */
152    private int findLastPosition(final DetailNode detailNode) {
153        final int lastPosition;
154        if (detailNode.getChildren().length == 0) {
155            lastPosition = lines2position.get(detailNode.getLineNumber())
156                    + detailNode.getColumnNumber() + detailNode.getText().length();
157        }
158        else {
159            final DetailNode lastChild =
160                    detailNode.getChildren()[detailNode.getChildren().length - 1];
161            lastPosition = findLastPosition(lastChild);
162        }
163        return lastPosition;
164    }
165
166}