1313 */
1414package org .eclipse .jface .internal .text .codemining ;
1515
16- import java .util .ArrayList ;
17- import java .util .List ;
1816import java .util .function .Consumer ;
19- import java .util .stream .Stream ;
2017
21- import org .eclipse .swt .custom .StyledText ;
2218import org .eclipse .swt .events .MouseEvent ;
23- import org .eclipse .swt .graphics .Color ;
24- import org .eclipse .swt .graphics .GC ;
25- import org .eclipse .swt .graphics .Point ;
26- import org .eclipse .swt .graphics .Rectangle ;
27-
28- import org .eclipse .core .runtime .IProgressMonitor ;
2919
3020import org .eclipse .jface .text .Position ;
31- import org .eclipse .jface .text .codemining .ICodeMining ;
3221import org .eclipse .jface .text .source .ISourceViewer ;
33- import org .eclipse .jface .text .source .inlined .LineHeaderAnnotation ;
3422
3523/**
3624 * Code Mining annotation in line header.
3725 *
3826 * @since 3.13
3927 */
40- public class CodeMiningLineHeaderAnnotation extends LineHeaderAnnotation implements ICodeMiningAnnotation {
41-
42- private static final String SEPARATOR = " | " ; //$NON-NLS-1$
43-
44- /**
45- * List of resolved minings which contains current resolved minings and last resolved minings
46- * and null if mining is not resolved.
47- */
48- private ICodeMining [] fResolvedMinings ;
49-
50- /**
51- * List of current resolved/unresolved minings
52- */
53- private final List <ICodeMining > fMinings ;
54-
55- /**
56- * List of bounds minings
57- */
58- private final List <Rectangle > fBounds ;
59-
60- /**
61- * The current progress monitor
62- */
63- private IProgressMonitor fMonitor ;
28+ public class CodeMiningLineHeaderAnnotation extends CodeMiningMultilineAnnotation {
6429
6530 /**
6631 * Code mining annotation constructor.
@@ -85,204 +50,5 @@ public CodeMiningLineHeaderAnnotation(Position position, ISourceViewer viewer) {
8550 */
8651 public CodeMiningLineHeaderAnnotation (Position position , ISourceViewer viewer , Consumer <MouseEvent > onMouseHover , Consumer <MouseEvent > onMouseOut , Consumer <MouseEvent > onMouseMove ) {
8752 super (position , viewer , onMouseHover , onMouseOut , onMouseMove );
88- fResolvedMinings = null ;
89- fMinings = new ArrayList <>();
90- fBounds = new ArrayList <>();
91- }
92-
93- @ Override
94- public int getHeight () {
95- return hasAtLeastOneResolvedMiningNotEmpty () ? getMultilineHeight (null ) : 0 ;
96- }
97-
98- public int getHeight (GC gc ) {
99- return hasAtLeastOneResolvedMiningNotEmpty () ? getMultilineHeight (gc ) : 0 ;
100- }
101-
102- private int getMultilineHeight (GC gc ) {
103- int numLinesOfAllMinings = 0 ;
104- StyledText styledText = super .getTextWidget ();
105- boolean ignoreFirstLine = false ;
106- int sumLineHeight = 0 ;
107- for (int i = 0 ; i < fMinings .size (); i ++) {
108- ICodeMining mining = fMinings .get (i );
109- String label = mining .getLabel ();
110- if (label == null ) {
111- continue ;
112- }
113- String [] splitted = label .split ("\\ r?\\ n|\\ r" ); //$NON-NLS-1$
114- int numLines = splitted .length ;
115- if (ignoreFirstLine ) {
116- numLines --;
117- }
118- numLinesOfAllMinings += numLines ;
119- if (gc != null ) {
120- sumLineHeight = calculateLineHeight (gc , styledText , ignoreFirstLine , sumLineHeight , i , splitted );
121- }
122- ignoreFirstLine = true ;
123- }
124- if (sumLineHeight == 0 ) {
125- return super .getHeight ();
126- }
127- if (gc != null ) {
128- return sumLineHeight ;
129- } else {
130- int lineHeight = styledText .getLineHeight ();
131- int result = numLinesOfAllMinings * (lineHeight + styledText .getLineSpacing ());
132- return result ;
133- }
134- }
135-
136- private int calculateLineHeight (GC gc , StyledText styledText , boolean ignoreFirstLine , int sumLineHeight , int miningIndex , String [] splitted ) {
137- for (int j = 0 ; j < splitted .length ; j ++) {
138- String line = splitted [j ];
139- if (j == 0 && ignoreFirstLine ) {
140- continue ;
141- }
142- if (j == splitted .length - 1 && miningIndex + 1 < fMinings .size ()) { // last line, take first line from next mining
143- String nextLabel = fMinings .get (miningIndex + 1 ).getLabel ();
144- if (nextLabel != null ) {
145- String firstFromNext = nextLabel .split ("\\ r?\\ n|\\ r" )[0 ]; //$NON-NLS-1$
146- line += firstFromNext ;
147- }
148- }
149- Point ext = gc .textExtent (line );
150- sumLineHeight += ext .y + styledText .getLineSpacing ();
151- }
152- return sumLineHeight ;
153- }
154-
155- /**
156- * Returns <code>true</code> if the annotation has at least one resolved mining which have a
157- * label and <code>false</code> otherwise.
158- *
159- * @return <code>true</code> if the annotation has at least one resolved mining which have a
160- * label and <code>false</code> otherwise.
161- */
162- private boolean hasAtLeastOneResolvedMiningNotEmpty () {
163- if (fMinings .stream ().anyMatch (m -> m .getLabel () != null && !m .getLabel ().isEmpty ())) {
164- return true ; // will have a resolved mining.
165- }
166-
167- if (fResolvedMinings == null || fResolvedMinings .length == 0 ) {
168- return false ;
169- }
170- return Stream .of (fResolvedMinings ).anyMatch (CodeMiningManager ::isValidMining );
171- }
172-
173- @ Override
174- public void update (List <ICodeMining > minings , IProgressMonitor monitor ) {
175- if (fResolvedMinings == null || (fResolvedMinings .length != minings .size ())) {
176- // size of resolved minings are different from size of minings to update, initialize it with size of minings to update
177- fResolvedMinings = new ICodeMining [minings .size ()];
178- }
179- // fill valid resolved minings with old minings.
180- int length = Math .min (fMinings .size (), minings .size ());
181- for (int i = 0 ; i < length ; i ++) {
182- ICodeMining mining = fMinings .get (i );
183- if (mining .getLabel () != null ) {
184- fResolvedMinings [i ]= mining ;
185- }
186- }
187- disposeMinings ();
188- fMonitor = monitor ;
189- fMinings .addAll (minings );
190- }
191-
192- @ Override
193- public void markDeleted (boolean deleted ) {
194- super .markDeleted (deleted );
195- if (deleted ) {
196- disposeMinings ();
197- fResolvedMinings = null ;
198- }
199- }
200-
201- private void disposeMinings () {
202- fMinings .stream ().forEach (ICodeMining ::dispose );
203- fMinings .clear ();
204- }
205-
206- @ Override
207- public void draw (GC gc , StyledText textWidget , int offset , int length , Color color , int x , int y ) {
208- List <ICodeMining > minings = new ArrayList <>(fMinings );
209- int nbDraw = 0 ;
210- int separatorWidth = -1 ;
211- boolean redrawn = false ;
212- fBounds .clear ();
213- int singleLineHeight = super .getHeight ();
214- int lineSpacing = textWidget .getLineSpacing ();
215- for (int i = 0 ; i < minings .size (); i ++) {
216- ICodeMining mining = minings .get (i );
217- // try to get the last resolved mining.
218- ICodeMining lastResolvedMining = (fResolvedMinings != null && fResolvedMinings .length > i ) ? fResolvedMinings [i ] : null ;
219- if (mining .getLabel () != null ) {
220- // mining is resolved without error, update the resolved mining list
221- fResolvedMinings [i ]= mining ;
222- } else if (!mining .isResolved ()) {
223- // the mining is not resolved, draw the last resolved mining
224- mining = lastResolvedMining ;
225- if (!redrawn ) {
226- // redraw the annotation when mining is resolved.
227- redraw ();
228- redrawn = true ;
229- }
230- } else {
231- // the mining is resolved with error, draw the last resolved mining
232- mining = lastResolvedMining ;
233- }
234- if (!CodeMiningManager .isValidMining (mining )) {
235- // ignore the draw of mining
236- continue ;
237- }
238- // draw the mining
239- if (nbDraw > 0 ) {
240- gc .drawText (SEPARATOR , x , y );
241- if (separatorWidth == -1 ) {
242- separatorWidth = gc .stringExtent (SEPARATOR ).x ;
243- }
244- x += separatorWidth ;
245- }
246- Point loc = null ;
247- if (mining != null ) {
248- loc = mining .draw (gc , textWidget , color , x , y );
249- }
250- if (loc != null ) {
251- fBounds .add (new Rectangle (x , y , loc .x , loc .y ));
252- x += loc .x ;
253- if (loc .y > singleLineHeight ) {
254- y += loc .y + lineSpacing - singleLineHeight ;
255- }
256- }
257- nbDraw ++;
258- }
259- }
260-
261- @ Override
262- public void redraw () {
263- // redraw codemining annotation is done only if all current minings are resolved.
264- List <ICodeMining > minings = new ArrayList <>(fMinings );
265- for (ICodeMining mining : minings ) {
266- if (!mining .isResolved ()) {
267- // one of mining is not resolved, resolve it and then redraw the annotation.
268- mining .resolve (getViewer (), fMonitor ).thenRunAsync (() -> {
269- this .redraw ();
270- });
271- return ;
272- }
273- }
274- // all minings are resolved, redraw the annotation
275- super .redraw ();
276- }
277-
278- @ Override
279- public Consumer <MouseEvent > getAction (MouseEvent e ) {
280- ICodeMining mining = CodeMiningManager .getValidCodeMiningAtLocation (fResolvedMinings , fBounds , e .x , e .y );
281- return mining != null ? mining .getAction () : null ;
282- }
283-
284- @ Override
285- public boolean isInVisibleLines () {
286- return super .isInVisibleLines ();
28753 }
28854}
0 commit comments