11package  root .javafx .CustomView ;
22
33import  java .io .IOException ;
4- 
4+ import  java .util .Collection ;
5+ import  java .util .Collections ;
6+ import  java .util .function .Consumer ;
7+ import  java .util .function .Function ;
8+ import  java .util .regex .Matcher ;
9+ import  java .util .regex .Pattern ;
10+ 
11+ import  org .fxmisc .richtext .GenericStyledArea ;
512import  org .fxmisc .richtext .StyleClassedTextArea ;
13+ import  org .fxmisc .richtext .model .Paragraph ;
14+ import  org .fxmisc .richtext .model .StyleSpans ;
15+ import  org .fxmisc .richtext .model .StyleSpansBuilder ;
16+ import  org .reactfx .collection .ListModification ;
617
718import  de .jensd .fx .glyphs .fontawesome .FontAwesomeIconView ;
19+ import  javafx .application .Platform ;
820import  javafx .fxml .FXML ;
921import  javafx .fxml .FXMLLoader ;
1022import  javafx .geometry .Insets ;
2436public  class  AlertLogListViewCell  extends  ListCell <Log > {
2537	private  FXMLLoader  loader ;
2638
39+ 	private  Pattern  KEYWORD_PATTERN ;
40+ 
2741	@ FXML 
2842	AnchorPane  rootAP ;
2943	@ FXML 
@@ -36,6 +50,11 @@ public class AlertLogListViewCell extends ListCell<Log> {
3650	HBox  logContentHBox ;
3751
3852	public  AlertLogListViewCell (String ... highlightKeywords ) {
53+ 		String  join  = String .join ("|" , highlightKeywords );
54+ 		KEYWORD_PATTERN  = Pattern .compile ("(?<KEYWORD1>\\ b("  + join  + ")\\ b)" 
55+ 				+ "|(?<KEYWORD2>\\ b("  + join  + ")\\ B)" 
56+ 						+ "|(?<KEYWORD3>\\ B("  + join  + ")\\ b)" 
57+ 								+ "|(?<KEYWORD4>\\ B("  + join  + ")\\ B)" );
3958	}
4059
4160	@ Override 
@@ -80,6 +99,8 @@ protected void updateItem(Log logObj, boolean empty) {
8099			codeArea .getStylesheets ()
81100					.add (getClass ().getResource (baseDir  + "/css/alertLogListViewCell.css" ).toExternalForm ());
82101			codeArea .getStyleClass ().add ("code-area" );
102+ 			codeArea .getVisibleParagraphs ()
103+ 					.addModificationObserver (new  VisibleParagraphStyler <>(codeArea , this ::computeHighlighting ));
83104
84105			codeArea .replaceText (0 , 0 , logObj .getFullLogString ());
85106			if  (isErrorLog ) {
@@ -109,4 +130,51 @@ private boolean isErrorLog(String logContent) {
109130		// TODO Remove hard-coding that identifying error log 
110131		return  logContent .contains ("ORA-" );
111132	}
133+ 
134+ 	private  StyleSpans <Collection <String >> computeHighlighting (String  text ) {
135+ 		Matcher  matcher  = KEYWORD_PATTERN .matcher (text );
136+ 		int  lastKeywordEnd  = 0 ;
137+ 		StyleSpansBuilder <Collection <String >> spansBuilder  = new  StyleSpansBuilder <>();
138+ 		while  (matcher .find ()) {
139+ 			String  styleClass  = matcher .group ("KEYWORD1" ) != null  ? "keyword" 
140+ 					: matcher .group ("KEYWORD2" ) != null  ? "keyword" 
141+ 							: matcher .group ("KEYWORD3" ) != null  ? "keyword" 
142+ 									: matcher .group ("KEYWORD4" ) != null  ? "keyword"  : null ;
143+ 			spansBuilder .add (Collections .emptyList (), matcher .start () - lastKeywordEnd );
144+ 			spansBuilder .add (Collections .singleton (styleClass ), matcher .end () - matcher .start ());
145+ 			lastKeywordEnd  = matcher .end ();
146+ 		}
147+ 		spansBuilder .add (Collections .emptyList (), text .length () - lastKeywordEnd );
148+ 
149+ 		return  spansBuilder .create ();
150+ 	}
151+ 
152+ 	private  class  VisibleParagraphStyler <PS , SEG , S >
153+ 			implements  Consumer <ListModification <? extends  Paragraph <PS , SEG , S >>> {
154+ 		private  final  GenericStyledArea <PS , SEG , S > area ;
155+ 		private  final  Function <String , StyleSpans <S >> computeStyles ;
156+ 		private  int  prevParagraph , prevTextLength ;
157+ 
158+ 		public  VisibleParagraphStyler (GenericStyledArea <PS , SEG , S > area ,
159+ 				Function <String , StyleSpans <S >> computeStyles ) {
160+ 			this .computeStyles  = computeStyles ;
161+ 			this .area  = area ;
162+ 		}
163+ 
164+ 		@ Override 
165+ 		public  void  accept (ListModification <? extends  Paragraph <PS , SEG , S >> lm ) {
166+ 			if  (lm .getAddedSize () > 0 ) {
167+ 				int  paragraph  = Math .min (area .firstVisibleParToAllParIndex () + lm .getFrom (),
168+ 						area .getParagraphs ().size () - 1 );
169+ 				String  text  = area .getText (paragraph , 0 , paragraph , area .getParagraphLength (paragraph ));
170+ 
171+ 				if  (paragraph  != prevParagraph  || text .length () != prevTextLength ) {
172+ 					int  startPos  = area .getAbsolutePosition (paragraph , 0 );
173+ 					Platform .runLater (() -> area .setStyleSpans (startPos , computeStyles .apply (text )));
174+ 					prevTextLength  = text .length ();
175+ 					prevParagraph  = paragraph ;
176+ 				}
177+ 			}
178+ 		}
179+ 	}
112180}
0 commit comments