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.util.List;
23
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.DetailNode;
26 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
27
28 /**
29 * Presentation model for CodeSelector.
30 */
31 public class CodeSelectorPresentation {
32
33 /** DetailAST or DetailNode node. */
34 private final Object node;
35 /** Mapping. */
36 private final List<Integer> lines2position;
37 /** Selection start position. */
38 private int selectionStart;
39 /** Selection end position. */
40 private int selectionEnd;
41
42 /**
43 * Constructor.
44 *
45 * @param ast ast node.
46 * @param lines2position positions of lines.
47 * @noinspection AssignmentOrReturnOfFieldWithMutableType
48 * @noinspectionreason AssignmentOrReturnOfFieldWithMutableType - mutability is
49 * expected in list of lines of code
50 */
51 public CodeSelectorPresentation(DetailAST ast, List<Integer> lines2position) {
52 node = ast;
53 this.lines2position = lines2position;
54 }
55
56 /**
57 * Constructor.
58 *
59 * @param node DetailNode node.
60 * @param lines2position list to map lines.
61 * @noinspection AssignmentOrReturnOfFieldWithMutableType
62 * @noinspectionreason AssignmentOrReturnOfFieldWithMutableType - mutability is expected
63 * in list of lines of code
64 */
65 public CodeSelectorPresentation(DetailNode node, List<Integer> lines2position) {
66 this.node = node;
67 this.lines2position = lines2position;
68 }
69
70 /**
71 * Returns selection start position.
72 *
73 * @return selection start position.
74 */
75 public int getSelectionStart() {
76 return selectionStart;
77 }
78
79 /**
80 * Returns selection end position.
81 *
82 * @return selection end position.
83 */
84 public int getSelectionEnd() {
85 return selectionEnd;
86 }
87
88 /**
89 * Find start and end selection positions from AST line and Column.
90 */
91 public void findSelectionPositions() {
92 if (node instanceof DetailAST detailAst) {
93 findSelectionPositions(detailAst);
94 }
95 else {
96 findSelectionPositions((DetailNode) node);
97 }
98 }
99
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.getFirstChild() == null) {
155 lastPosition = lines2position.get(detailNode.getLineNumber())
156 + detailNode.getColumnNumber() + detailNode.getText().length();
157 }
158 else {
159 DetailNode firstChild = detailNode.getFirstChild();
160 while (firstChild.getNextSibling() != null) {
161 firstChild = firstChild.getNextSibling();
162 }
163 lastPosition = findLastPosition(firstChild);
164 }
165 return lastPosition;
166 }
167
168 }