21
21
package org .eclipse .text .quicksearch .internal .ui ;
22
22
23
23
import static org .eclipse .jface .resource .JFaceResources .TEXT_FONT ;
24
+ import static org .eclipse .ui .texteditor .AbstractDecoratedTextEditorPreferenceConstants .EDITOR_CURRENT_LINE ;
25
+ import static org .eclipse .ui .texteditor .AbstractDecoratedTextEditorPreferenceConstants .EDITOR_CURRENT_LINE_COLOR ;
26
+ import static org .eclipse .ui .texteditor .AbstractDecoratedTextEditorPreferenceConstants .EDITOR_LINE_NUMBER_RULER_COLOR ;
27
+ import static org .eclipse .ui .texteditor .AbstractTextEditor .PREFERENCE_COLOR_BACKGROUND ;
28
+ import static org .eclipse .ui .texteditor .AbstractTextEditor .PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT ;
29
+ import static org .eclipse .ui .texteditor .AbstractTextEditor .PREFERENCE_COLOR_FOREGROUND ;
30
+ import static org .eclipse .ui .texteditor .AbstractTextEditor .PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT ;
24
31
25
32
import java .util .ArrayList ;
26
33
import java .util .Arrays ;
46
53
import org .eclipse .jface .dialogs .IDialogConstants ;
47
54
import org .eclipse .jface .dialogs .IDialogSettings ;
48
55
import org .eclipse .jface .layout .GridDataFactory ;
56
+ import org .eclipse .jface .preference .PreferenceConverter ;
49
57
import org .eclipse .jface .resource .JFaceResources ;
50
58
import org .eclipse .jface .text .BadLocationException ;
59
+ import org .eclipse .jface .text .CursorLinePainter ;
51
60
import org .eclipse .jface .text .IDocument ;
52
61
import org .eclipse .jface .text .IRegion ;
62
+ import org .eclipse .jface .text .source .CompositeRuler ;
63
+ import org .eclipse .jface .text .source .ISharedTextColors ;
64
+ import org .eclipse .jface .text .source .LineNumberRulerColumn ;
65
+ import org .eclipse .jface .text .source .SourceViewer ;
66
+ import org .eclipse .jface .util .IPropertyChangeListener ;
67
+ import org .eclipse .jface .util .PropertyChangeEvent ;
53
68
import org .eclipse .jface .viewers .ILazyContentProvider ;
54
69
import org .eclipse .jface .viewers .IStructuredContentProvider ;
55
70
import org .eclipse .jface .viewers .IStructuredSelection ;
67
82
import org .eclipse .swt .accessibility .ACC ;
68
83
import org .eclipse .swt .accessibility .AccessibleAdapter ;
69
84
import org .eclipse .swt .accessibility .AccessibleEvent ;
85
+ import org .eclipse .swt .custom .LineBackgroundEvent ;
86
+ import org .eclipse .swt .custom .LineBackgroundListener ;
70
87
import org .eclipse .swt .custom .SashForm ;
71
88
import org .eclipse .swt .custom .StyleRange ;
72
89
import org .eclipse .swt .custom .StyledText ;
81
98
import org .eclipse .swt .graphics .Color ;
82
99
import org .eclipse .swt .graphics .Image ;
83
100
import org .eclipse .swt .graphics .Point ;
101
+ import org .eclipse .swt .graphics .RGB ;
84
102
import org .eclipse .swt .graphics .Rectangle ;
103
+ import org .eclipse .swt .layout .FillLayout ;
85
104
import org .eclipse .swt .layout .GridData ;
86
105
import org .eclipse .swt .layout .GridLayout ;
87
106
import org .eclipse .swt .widgets .Button ;
107
+ import org .eclipse .swt .widgets .Canvas ;
88
108
import org .eclipse .swt .widgets .Combo ;
89
109
import org .eclipse .swt .widgets .Composite ;
90
110
import org .eclipse .swt .widgets .Control ;
111
131
import org .eclipse .ui .PartInitException ;
112
132
import org .eclipse .ui .PlatformUI ;
113
133
import org .eclipse .ui .dialogs .SelectionStatusDialog ;
134
+ import org .eclipse .ui .editors .text .EditorsUI ;
114
135
import org .eclipse .ui .handlers .IHandlerActivation ;
115
136
import org .eclipse .ui .handlers .IHandlerService ;
116
137
import org .eclipse .ui .internal .IWorkbenchGraphicConstants ;
117
138
import org .eclipse .ui .internal .WorkbenchImages ;
118
139
import org .eclipse .ui .internal .ide .IDEWorkbenchPlugin ;
119
140
import org .eclipse .ui .progress .UIJob ;
141
+ import org .eclipse .ui .texteditor .SourceViewerDecorationSupport ;
120
142
import org .osgi .framework .FrameworkUtil ;
121
143
122
144
/**
@@ -359,7 +381,10 @@ public void update(ViewerCell cell) {
359
381
360
382
private QuickTextSearcher searcher ;
361
383
362
- private StyledText details ;
384
+ private SourceViewer viewer ;
385
+ private LineNumberRulerColumn lineNumberColumn ;
386
+ private FixedLineHighlighter targetLineHighlighter ;
387
+ private final IPropertyChangeListener preferenceChangeListener = this ::handlePropertyChangeEvent ;
363
388
364
389
private DocumentFetcher documents ;
365
390
@@ -398,6 +423,7 @@ public QuickSearchDialog(IWorkbenchWindow window) {
398
423
MAX_LINE_LEN = QuickSearchActivator .getDefault ().getPreferences ().getMaxLineLen ();
399
424
MAX_RESULTS = QuickSearchActivator .getDefault ().getPreferences ().getMaxResults ();
400
425
progressJob .setSystem (true );
426
+ EditorsUI .getPreferenceStore ().addPropertyChangeListener (preferenceChangeListener );
401
427
}
402
428
403
429
/*
@@ -946,31 +972,124 @@ protected void dispose() {
946
972
blankImage .dispose ();
947
973
blankImage = null ;
948
974
}
975
+ EditorsUI .getPreferenceStore ().removePropertyChangeListener (preferenceChangeListener );
949
976
}
950
977
951
978
private void createDetailsArea (Composite parent ) {
952
- details = new StyledText (parent , SWT .MULTI +SWT .READ_ONLY +SWT .BORDER +SWT .H_SCROLL +SWT .V_SCROLL );
953
- details .setFont (JFaceResources .getFont (TEXT_FONT ));
979
+ var viewerParent = new Canvas (parent , SWT .BORDER );
980
+ viewerParent .setLayout (new FillLayout ());
981
+
982
+ viewer = new SourceViewer (viewerParent , new CompositeRuler (), SWT .H_SCROLL | SWT .V_SCROLL | SWT .READ_ONLY );
983
+ viewer .getTextWidget ().setFont (JFaceResources .getFont (TEXT_FONT ));
984
+ createViewerDecorations ();
954
985
955
986
list .addSelectionChangedListener (event -> refreshDetails ());
956
- details .addControlListener (new ControlAdapter () {
987
+
988
+ viewer .getTextWidget ().addControlListener (new ControlAdapter () {
957
989
@ Override
958
990
public void controlResized (ControlEvent e ) {
959
991
refreshDetails ();
960
992
}
961
993
});
962
994
}
963
995
996
+ private void setColors () {
997
+ RGB background = null ;
998
+ RGB foreground = null ;
999
+ var textWidget = viewer .getTextWidget ();
1000
+ ISharedTextColors sharedColors = EditorsUI .getSharedTextColors ();
1001
+
1002
+ var isUsingSystemBackground = EditorsUI .getPreferenceStore ().getBoolean (PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT );
1003
+ if (!isUsingSystemBackground ) {
1004
+ background = getColorFromStore (PREFERENCE_COLOR_BACKGROUND );
1005
+ }
1006
+ if (background != null ) {
1007
+ var color = sharedColors .getColor (background );
1008
+ textWidget .setBackground (color );
1009
+ lineNumberColumn .setBackground (color );
1010
+ } else {
1011
+ textWidget .setBackground (null );
1012
+ lineNumberColumn .setBackground (null );
1013
+ }
1014
+
1015
+ var isUsingSystemForeground = EditorsUI .getPreferenceStore ().getBoolean (PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT );
1016
+ if (!isUsingSystemForeground ) {
1017
+ foreground = getColorFromStore (PREFERENCE_COLOR_FOREGROUND );
1018
+ }
1019
+ if (foreground != null ) {
1020
+ textWidget .setForeground (sharedColors .getColor (foreground ));
1021
+ } else {
1022
+ textWidget .setForeground (null );
1023
+ }
1024
+ }
1025
+
1026
+ private Color getLineNumbersColor () {
1027
+ var lineNumbersColor = getColorFromStore (EDITOR_LINE_NUMBER_RULER_COLOR );
1028
+ return EditorsUI .getSharedTextColors ().getColor (lineNumbersColor == null ? new RGB (0 , 0 , 0 ) : lineNumbersColor );
1029
+ }
1030
+
1031
+ private Color getTargetLineHighlightColor () {
1032
+ RGB background = getColorFromStore (EDITOR_CURRENT_LINE_COLOR );
1033
+ ISharedTextColors sharedColors = EditorsUI .getSharedTextColors ();
1034
+ return sharedColors .getColor (background );
1035
+ }
1036
+
1037
+ private void createViewerDecorations () {
1038
+ lineNumberColumn = new LineNumberRulerColumn ();
1039
+ lineNumberColumn .setForeground (getLineNumbersColor ());
1040
+ viewer .addVerticalRulerColumn (lineNumberColumn );
1041
+
1042
+ var sourceViewerDecorationSupport = new SourceViewerDecorationSupport (viewer , null , null , EditorsUI .getSharedTextColors ());
1043
+ sourceViewerDecorationSupport .setCursorLinePainterPreferenceKeys (EDITOR_CURRENT_LINE , EDITOR_CURRENT_LINE_COLOR );
1044
+ sourceViewerDecorationSupport .install (EditorsUI .getPreferenceStore ());
1045
+ targetLineHighlighter = new FixedLineHighlighter ();
1046
+ targetLineHighlighter .highlightColor = getTargetLineHighlightColor ();
1047
+ viewer .getTextWidget ().addLineBackgroundListener (targetLineHighlighter );
1048
+
1049
+ setColors ();
1050
+ }
1051
+
1052
+ private void handlePropertyChangeEvent (PropertyChangeEvent event ) {
1053
+ if (viewer == null ) {
1054
+ return ;
1055
+ }
1056
+ var prop = event .getProperty ();
1057
+ if (PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT .equals (prop )
1058
+ || PREFERENCE_COLOR_BACKGROUND .equals (prop )
1059
+ || PREFERENCE_COLOR_FOREGROUND_SYSTEM_DEFAULT .equals (prop )
1060
+ || PREFERENCE_COLOR_FOREGROUND .equals (prop )) {
1061
+ setColors ();
1062
+ viewer .getTextWidget ().redraw ();
1063
+ } else if (EDITOR_LINE_NUMBER_RULER_COLOR .equals (prop )) {
1064
+ lineNumberColumn .setForeground (getLineNumbersColor ());
1065
+ lineNumberColumn .redraw ();
1066
+ } else if (EDITOR_CURRENT_LINE_COLOR .equals (prop )) {
1067
+ targetLineHighlighter .highlightColor = getTargetLineHighlightColor ();
1068
+ viewer .getTextWidget ().redraw ();
1069
+ }
1070
+ }
1071
+
1072
+ private RGB getColorFromStore (String key ) {
1073
+ var store = EditorsUI .getPreferenceStore ();
1074
+ RGB rgb = null ;
1075
+ if (store .contains (key )) {
1076
+ if (store .isDefault (key )) {
1077
+ rgb = PreferenceConverter .getDefaultColor (store , key );
1078
+ } else {
1079
+ rgb = PreferenceConverter .getColor (store , key );
1080
+ }
1081
+ }
1082
+ return rgb ;
1083
+ }
964
1084
965
- // Dumber version just using the a 'raw' StyledText widget.
966
1085
private void refreshDetails () {
967
- if (details !=null && list !=null && !list .getTable ().isDisposed ()) {
1086
+ if (viewer !=null && list !=null && !list .getTable ().isDisposed ()) {
968
1087
if (documents ==null ) {
969
1088
documents = new DocumentFetcher ();
970
1089
}
971
1090
IStructuredSelection sel = (IStructuredSelection ) list .getSelection ();
972
1091
if (sel ==null || sel .isEmpty ()) {
973
- details . setText ( EMPTY_STRING );
1092
+ viewer . setDocument ( null );
974
1093
} else {
975
1094
//Not empty selection
976
1095
final int context = 100 ; // number of lines before and after match to include in preview
@@ -983,35 +1102,57 @@ private void refreshDetails() {
983
1102
int line = item .getLineNumber ()-1 ; //in document lines are 0 based. In search 1 based.
984
1103
int contextStartLine = Math .max (line -(numLines -1 )/2 - context , 0 );
985
1104
int start = document .getLineOffset (contextStartLine );
1105
+ int displayedEndLine = line + numLines /2 ;
986
1106
int end = document .getLength ();
987
- try {
988
- IRegion lineInfo = document .getLineInformation (line + numLines /2 + context );
989
- end = lineInfo .getOffset () + lineInfo .getLength ();
990
- } catch (BadLocationException e ) {
991
- //Presumably line number is past the end of document.
992
- //ignore.
1107
+ if (displayedEndLine + context <= document .getNumberOfLines ()) {
1108
+ try {
1109
+ IRegion lineInfo = document .getLineInformation (displayedEndLine + context );
1110
+ end = lineInfo .getOffset () + lineInfo .getLength ();
1111
+ } catch (BadLocationException e ) {
1112
+ //Presumably line number is past the end of document.
1113
+ //ignore.
1114
+ }
993
1115
}
1116
+ int contextLenght = end -start ;
1117
+
1118
+ viewer .setDocument (document );
1119
+ viewer .setVisibleRegion (start , contextLenght );
1120
+
1121
+ targetLineHighlighter .setTargetLineOffset (item .getOffset () - start );
994
1122
995
- StyledString styledString = highlightMatches (document .get (start , end -start ));
996
- details .setText (styledString .getString ());
997
- details .setStyleRanges (styledString .getStyleRanges ());
998
- details .setTopIndex (Math .max (line - contextStartLine - numLines /2 , 0 ));
1123
+ // center target line in the displayed area
1124
+ IRegion rangeEndLineInfo = document .getLineInformation (Math .min (displayedEndLine , document .getNumberOfLines () - 1 ));
1125
+ int rangeStart = document .getLineOffset (Math .max (line - numLines /2 , 0 ));
1126
+ int rangeEnd = rangeEndLineInfo .getOffset () + rangeEndLineInfo .getLength ();
1127
+ viewer .revealRange (rangeStart , rangeEnd - rangeStart );
1128
+
1129
+ var targetLineFirstMatch = getQuery ().findFirst (document .get (item .getOffset (), contextLenght - (item .getOffset () - start )));
1130
+ int targetLineFirstMatchStart = item .getOffset () + targetLineFirstMatch .getOffset ();
1131
+ // sets caret position
1132
+ viewer .setSelectedRange (targetLineFirstMatchStart , 0 );
1133
+ // does horizontal scrolling if necessary to reveal 1st occurrence in target line
1134
+ viewer .revealRange (targetLineFirstMatchStart , targetLineFirstMatch .getLength ());
1135
+
1136
+ // above setVisibleRegion() call makes these ranges to be aligned with content of text widget
1137
+ StyledString styledString = highlightMatches (document .get (start , contextLenght ));
1138
+ viewer .getTextWidget ().setStyleRanges (styledString .getStyleRanges ());
999
1139
return ;
1000
1140
} catch (BadLocationException e ) {
1001
1141
}
1002
1142
}
1003
1143
}
1004
1144
}
1005
1145
//empty selection or some error:
1006
- details . setText ( EMPTY_STRING );
1146
+ viewer . setDocument ( null );
1007
1147
}
1008
1148
}
1009
1149
1010
1150
/**
1011
1151
* Computes how many lines of text can be displayed in the details section.
1012
1152
*/
1013
1153
private int computeLines () {
1014
- if (details !=null && !details .isDisposed ()) {
1154
+ StyledText details ;
1155
+ if (viewer !=null && !(details = viewer .getTextWidget ()).isDisposed ()) {
1015
1156
int lineHeight = details .getLineHeight ();
1016
1157
int areaHeight = details .getClientArea ().height ;
1017
1158
return (areaHeight + lineHeight - 1 ) / lineHeight ;
@@ -1034,47 +1175,6 @@ private StyledString highlightMatches(String visibleText) {
1034
1175
return styledText ;
1035
1176
}
1036
1177
1037
- // Version using sourceviewer
1038
- // private void refreshDetails() {
1039
- // if (details!=null && list!=null && !list.getTable().isDisposed()) {
1040
- // if (documents==null) {
1041
- // documents = new DocumentFetcher();
1042
- // }
1043
- // IStructuredSelection sel = (IStructuredSelection) list.getSelection();
1044
- // if (sel!=null && !sel.isEmpty()) {
1045
- // //Not empty selection
1046
- // LineItem item = (LineItem) sel.getFirstElement();
1047
- // IDocument document = documents.getDocument(item.getFile());
1048
- // try {
1049
- // int line = item.getLineNumber()-1; //in document lines are 0 based. In search 1 based.
1050
- // int start = document.getLineOffset(Math.max(line-2, 0));
1051
- // int end = document.getLength();
1052
- // try {
1053
- // end = document.getLineOffset(line+3);
1054
- // } catch (BadLocationException e) {
1055
- // //Presumably line number is past the end of document.
1056
- // //ignore.
1057
- // }
1058
- // details.setDocument(document, start, end-start);
1059
- //
1060
- // String visibleText = document.get(start, end-start);
1061
- // List<TextRange> matches = getQuery().findAll(visibleText);
1062
- // Region visibleRegion = new Region(start, end-start);
1063
- // TextPresentation presentation = new TextPresentation(visibleRegion, 20);
1064
- // presentation.setDefaultStyleRange(new StyleRange(0, document.getLength(), null, null));
1065
- // for (TextRange m : matches) {
1066
- // presentation.addStyleRange(new StyleRange(m.start+start, m.len, null, YELLOW));
1067
- // }
1068
- // details.changeTextPresentation(presentation, true);
1069
- //
1070
- // return;
1071
- // } catch (BadLocationException e) {
1072
- // }
1073
- // }
1074
- // details.setDocument(null);
1075
- // }
1076
- // }
1077
-
1078
1178
/**
1079
1179
* Handle selection in the items list by updating labels of selected and
1080
1180
* unselected items and refresh the details field using the selection.
@@ -1471,4 +1571,29 @@ public QuickTextQuery getQuery() {
1471
1571
return searcher .getQuery ();
1472
1572
}
1473
1573
1574
+ /**
1575
+ * A line background listener that provides the color that is used for current line highlighting (what
1576
+ * {@link CursorLinePainter} does) but for single fixed line only and does so always regardless of show current
1577
+ * line highlighting on/off preference.
1578
+ *
1579
+ * @see CursorLinePainter
1580
+ */
1581
+ private static class FixedLineHighlighter implements LineBackgroundListener {
1582
+
1583
+ private int lineOffset = -1 ;
1584
+ private Color highlightColor ;
1585
+
1586
+ public void setTargetLineOffset (int lineOffset ) {
1587
+ this .lineOffset = lineOffset ;
1588
+ }
1589
+
1590
+ @ Override
1591
+ public void lineGetBackground (LineBackgroundEvent event ) {
1592
+ if (lineOffset == event .lineOffset ) {
1593
+ event .lineBackground = highlightColor ;
1594
+ }
1595
+ }
1596
+
1597
+ }
1598
+
1474
1599
}
0 commit comments