Skip to content

Commit 91762a5

Browse files
committed
Changed the functionality of the regex search with control decorations
1 parent 090a18a commit 91762a5

File tree

5 files changed

+141
-38
lines changed

5 files changed

+141
-38
lines changed

bundles/org.eclipse.search/search/org/eclipse/search/internal/ui/text/TextSearchPage.java

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
import org.eclipse.jface.dialogs.ErrorDialog;
5555
import org.eclipse.jface.dialogs.IDialogSettings;
5656
import org.eclipse.jface.fieldassist.ComboContentAdapter;
57-
import org.eclipse.jface.resource.JFaceColors;
57+
import org.eclipse.jface.fieldassist.ControlDecoration;
5858
import org.eclipse.jface.viewers.ISelection;
5959

6060
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
@@ -68,6 +68,7 @@
6868
import org.eclipse.ui.IWorkingSetManager;
6969
import org.eclipse.ui.PlatformUI;
7070
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
71+
import org.eclipse.ui.internal.SearchDecoration;
7172

7273
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
7374

@@ -140,8 +141,7 @@ public class TextSearchPage extends DialogPage implements ISearchPage, IReplaceP
140141
*/
141142
private String[] fPreviousExtensions;
142143
private Label fFileNamePatternDescription;
143-
144-
144+
private ControlDecoration fPatternDecoration;
145145
private static class SearchPatternData {
146146
public final boolean isCaseSensitive;
147147
public final boolean isRegExSearch;
@@ -450,6 +450,7 @@ public void setVisible(boolean visible) {
450450
}
451451

452452
final void updateOKStatus() {
453+
fPatternDecoration.hide();
453454
boolean regexStatus= validateRegex();
454455
getContainer().setPerformActionEnabled(regexStatus);
455456
}
@@ -479,24 +480,19 @@ public void createControl(Composite parent) {
479480
setControl(result);
480481
Dialog.applyDialogFont(result);
481482
PlatformUI.getWorkbench().getHelpSystem().setHelp(result, ISearchHelpContextIds.TEXT_SEARCH_PAGE);
482-
}
483+
}
483484

484485
private boolean validateRegex() {
486+
485487
if (fIsRegExCheckbox.getSelection()) {
486488
try {
487489
PatternConstructor.createPattern(fPattern.getText(), fIsCaseSensitive, true);
488490
} catch (PatternSyntaxException e) {
489-
String locMessage= e.getLocalizedMessage();
490-
int i= 0;
491-
while (i < locMessage.length() && "\n\r".indexOf(locMessage.charAt(i)) == -1) { //$NON-NLS-1$
492-
i++;
493-
}
494-
statusMessage(true, locMessage.substring(0, i)); // only take first line
491+
SearchDecoration.validateRegex(fPattern.getText(), fPatternDecoration);
495492
return false;
496493
}
497-
statusMessage(false, ""); //$NON-NLS-1$
498494
} else {
499-
statusMessage(false, SearchMessages.SearchPage_containingText_hint);
495+
fPatternDecoration.hide();
500496
}
501497
return true;
502498
}
@@ -512,6 +508,8 @@ private void addTextPatternControls(Composite group) {
512508

513509
// Pattern combo
514510
fPattern= new Combo(group, SWT.SINGLE | SWT.BORDER);
511+
fPatternDecoration = new ControlDecoration(fPattern, SWT.BOTTOM | SWT.LEFT);
512+
515513
// Not done here to prevent page from resizing
516514
// fPattern.setItems(getPreviousSearchPatterns());
517515
fPattern.addSelectionListener(new SelectionAdapter() {
@@ -561,7 +559,6 @@ public void widgetSelected(SelectionEvent e) {
561559
public void widgetSelected(SelectionEvent e) {
562560
fIsRegExSearch= fIsRegExCheckbox.getSelection();
563561
updateOKStatus();
564-
565562
writeConfiguration();
566563
fPatterFieldContentAssist.setEnabled(fIsRegExSearch);
567564
fIsWholeWordCheckbox.setEnabled(!fIsRegExSearch);
@@ -860,15 +857,4 @@ private void writeConfiguration() {
860857

861858
}
862859

863-
private void statusMessage(boolean error, String message) {
864-
fStatusLabel.setText(message);
865-
if (error) {
866-
fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
867-
}
868-
else {
869-
// use same color as another label to respect styling
870-
fStatusLabel.setForeground(fFileNamePatternDescription.getForeground());
871-
}
872-
}
873-
874860
}

bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/internal/findandreplace/overlay/FindReplaceOverlay.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.eclipse.jface.dialogs.IDialogSettings;
5252
import org.eclipse.jface.dialogs.IPageChangedListener;
5353
import org.eclipse.jface.dialogs.PageChangedEvent;
54+
import org.eclipse.jface.fieldassist.ControlDecoration;
5455
import org.eclipse.jface.fieldassist.TextContentAdapter;
5556
import org.eclipse.jface.layout.GridDataFactory;
5657
import org.eclipse.jface.layout.GridLayoutFactory;
@@ -67,6 +68,7 @@
6768
import org.eclipse.ui.IWorkbenchPartReference;
6869
import org.eclipse.ui.PlatformUI;
6970
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
71+
import org.eclipse.ui.internal.SearchDecoration;
7072
import org.eclipse.ui.internal.findandreplace.FindReplaceLogic;
7173
import org.eclipse.ui.internal.findandreplace.FindReplaceMessages;
7274
import org.eclipse.ui.internal.findandreplace.HistoryStore;
@@ -146,6 +148,7 @@ private final class KeyboardShortcuts {
146148
private Color normalTextForegroundColor;
147149
private boolean positionAtTop = true;
148150
private final TargetPartVisibilityHandler targetPartVisibilityHandler;
151+
private ControlDecoration searchBarDecoration;
149152
private ContentAssistCommandAdapter contentAssistSearchField, contentAssistReplaceField;
150153

151154
public FindReplaceOverlay(Shell parent, IWorkbenchPart part, IFindReplaceTarget target) {
@@ -581,6 +584,7 @@ private void createRegexSearchButton() {
581584
wholeWordSearchButton.setEnabled(findReplaceLogic.isAvailable(SearchOptions.WHOLE_WORD));
582585
updateIncrementalSearch();
583586
updateContentAssistAvailability();
587+
decorate();
584588
}).withShortcuts(KeyboardShortcuts.OPTION_REGEX).build();
585589
regexSearchButton.setSelection(findReplaceLogic.isActive(SearchOptions.REGEX));
586590
}
@@ -650,6 +654,7 @@ private void createSearchBar() {
650654
HistoryStore searchHistory = new HistoryStore(getDialogSettings(), "searchhistory", //$NON-NLS-1$
651655
HISTORY_SIZE);
652656
searchBar = new HistoryTextWrapper(searchHistory, searchBarContainer, SWT.SINGLE);
657+
searchBarDecoration = new ControlDecoration(searchBar, SWT.BOTTOM | SWT.LEFT);
653658
GridDataFactory.fillDefaults().grab(true, true).align(GridData.FILL, GridData.FILL).applyTo(searchBar);
654659
searchBar.forceFocus();
655660
searchBar.selectAll();
@@ -674,6 +679,9 @@ public void focusLost(FocusEvent e) {
674679
});
675680
searchBar.setMessage(FindReplaceMessages.FindReplaceOverlay_searchBar_message);
676681
contentAssistSearchField = createContentAssistField(searchBar, true);
682+
searchBar.addModifyListener(Event -> {
683+
decorate();
684+
});
677685
}
678686

679687
private void updateIncrementalSearch() {
@@ -1061,4 +1069,13 @@ private void setContentAssistsEnablement(boolean enable) {
10611069
private void updateContentAssistAvailability() {
10621070
setContentAssistsEnablement(findReplaceLogic.isAvailableAndActive(SearchOptions.REGEX));
10631071
}
1072+
1073+
private void decorate() {
1074+
if (regexSearchButton.getSelection()) {
1075+
SearchDecoration.validateRegex(getFindString(), searchBarDecoration);
1076+
} else {
1077+
searchBarDecoration.hide();
1078+
}
1079+
}
1080+
10641081
}

bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.eclipse.jface.dialogs.Dialog;
5050
import org.eclipse.jface.dialogs.IDialogSettings;
5151
import org.eclipse.jface.fieldassist.ComboContentAdapter;
52+
import org.eclipse.jface.fieldassist.ControlDecoration;
5253
import org.eclipse.jface.fieldassist.FieldDecoration;
5354
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
5455
import org.eclipse.jface.resource.JFaceColors;
@@ -64,13 +65,15 @@
6465

6566
import org.eclipse.ui.PlatformUI;
6667
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
68+
import org.eclipse.ui.internal.SearchDecoration;
6769
import org.eclipse.ui.internal.findandreplace.FindReplaceLogic;
6870
import org.eclipse.ui.internal.findandreplace.FindReplaceLogicMessageGenerator;
6971
import org.eclipse.ui.internal.findandreplace.FindReplaceMessages;
7072
import org.eclipse.ui.internal.findandreplace.HistoryStore;
7173
import org.eclipse.ui.internal.findandreplace.IFindReplaceLogic;
7274
import org.eclipse.ui.internal.findandreplace.SearchOptions;
7375
import org.eclipse.ui.internal.findandreplace.status.IFindReplaceStatus;
76+
import org.eclipse.ui.internal.findandreplace.status.InvalidRegExStatus;
7477
import org.eclipse.ui.internal.texteditor.SWTUtil;
7578

7679
/**
@@ -147,7 +150,10 @@ public void modifyText(ModifyEvent e) {
147150
fIgnoreNextEvent = false;
148151
return;
149152
}
150-
evaluateFindReplaceStatus();
153+
modificationHandler.run();
154+
fFindField.addModifyListener(event -> {
155+
decorate();
156+
});
151157

152158
updateButtonState(!findReplaceLogic.isActive(SearchOptions.INCREMENTAL));
153159
}
@@ -196,6 +202,7 @@ public void modifyText(ModifyEvent e) {
196202
* @since 3.0
197203
*/
198204
private boolean fGiveFocusToFindField = true;
205+
private ControlDecoration fFindFieldDecoration;
199206

200207
/**
201208
* Holds the mnemonic/button pairs for all buttons.
@@ -345,6 +352,7 @@ public void widgetSelected(SelectionEvent e) {
345352
evaluateFindReplaceStatus();
346353
}
347354
});
355+
348356
setGridData(fReplaceFindButton, SWT.FILL, false, SWT.FILL, false);
349357

350358
fReplaceSelectionButton = makeButton(panel, FindReplaceMessages.FindReplace_ReplaceSelectionButton_label, 104,
@@ -634,6 +642,8 @@ private Composite createInputPanel(Composite parent) {
634642
FindReplaceDocumentAdapterContentProposalProvider findProposer = new FindReplaceDocumentAdapterContentProposalProvider(
635643
true);
636644
fFindField = new Combo(panel, SWT.DROP_DOWN | SWT.BORDER);
645+
fFindFieldDecoration = new ControlDecoration(fFindField, SWT.BOTTOM | SWT.LEFT);
646+
637647
fContentAssistFindField = new ContentAssistCommandAdapter(fFindField, contentAdapter, findProposer,
638648
ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new char[0], true);
639649
setGridData(fFindField, SWT.FILL, true, SWT.CENTER, false);
@@ -750,6 +760,7 @@ public void widgetDefaultSelected(SelectionEvent e) {
750760
@Override
751761
public void widgetSelected(SelectionEvent e) {
752762
boolean newState = fIsRegExCheckBox.getSelection();
763+
decorate();
753764
setupFindReplaceLogic();
754765
storeSettings();
755766
updateButtonState();
@@ -1050,9 +1061,10 @@ private void addDecorationMargin(Control control) {
10501061
if (!(layoutData instanceof GridData))
10511062
return;
10521063
GridData gd = (GridData) layoutData;
1053-
FieldDecoration dec = FieldDecorationRegistry.getDefault()
1064+
1065+
FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault()
10541066
.getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
1055-
gd.horizontalIndent = dec.getImage().getBounds().width;
1067+
gd.horizontalIndent = fieldDecoration.getImage().getBounds().width;
10561068
}
10571069

10581070
/**
@@ -1102,7 +1114,6 @@ private void updateButtonState(boolean disableReplace) {
11021114
}
11031115
}
11041116

1105-
11061117
/**
11071118
* Updates the given combo with the given content.
11081119
*
@@ -1335,19 +1346,27 @@ private void activateInFindReplaceLogicIf(SearchOptions option, boolean shouldAc
13351346
}
13361347
}
13371348

1338-
/**
1339-
* Evaluate the status of the FindReplaceLogic object.
1340-
*/
1349+
private void decorate() {
1350+
if (fIsRegExCheckBox.getSelection()) {
1351+
SearchDecoration.validateRegex(fFindField.getText(), fFindFieldDecoration);
1352+
} else {
1353+
fFindFieldDecoration.hide();
1354+
}
1355+
}
1356+
13411357
private void evaluateFindReplaceStatus() {
13421358
IFindReplaceStatus status = findReplaceLogic.getStatus();
13431359

1344-
String dialogMessage = status.accept(new FindReplaceLogicMessageGenerator());
1345-
fStatusLabel.setText(dialogMessage);
1346-
if (status.isInputValid()) {
1347-
fStatusLabel.setForeground(fReplaceLabel.getForeground());
1348-
} else {
1349-
fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
1360+
if (!(status instanceof InvalidRegExStatus)) {
1361+
String dialogMessage = status.accept(new FindReplaceLogicMessageGenerator());
1362+
fStatusLabel.setText(dialogMessage);
1363+
if (status.isInputValid()) {
1364+
fStatusLabel.setForeground(fReplaceLabel.getForeground());
1365+
} else {
1366+
fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
1367+
}
13501368
}
1369+
13511370
}
13521371

13531372
private String getCurrentSelection() {

bundles/org.eclipse.ui/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Bundle-Activator: org.eclipse.ui.internal.UIPlugin
77
Bundle-ActivationPolicy: lazy
88
Bundle-Vendor: %Plugin.providerName
99
Bundle-Localization: plugin
10-
Export-Package: org.eclipse.ui.internal;x-internal:=true
10+
Export-Package: org.eclipse.ui.internal;x-friends:="org.eclipse.ui.workbench.texteditor,org.eclipse.search"
1111
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
1212
org.eclipse.swt;bundle-version="[3.126.0,4.0.0)";visibility:=reexport,
1313
org.eclipse.jface;bundle-version="[3.34.0,4.0.0)";visibility:=reexport,
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Vector Informatik GmbH and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Vector Informatik GmbH - initial API and implementation
13+
*******************************************************************************/
14+
15+
package org.eclipse.ui.internal;
16+
17+
import java.util.regex.Pattern;
18+
import java.util.regex.PatternSyntaxException;
19+
20+
import org.eclipse.jface.fieldassist.ControlDecoration;
21+
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
22+
import org.eclipse.swt.graphics.Image;
23+
24+
/**
25+
* This class contains methods to validate and decorate search fields.
26+
*/
27+
public class SearchDecoration {
28+
29+
private SearchDecoration() {
30+
// avoid instantiation
31+
}
32+
33+
/**
34+
* Validate the given regular expression and change the control decoration
35+
* accordingly. If the expression is invalid then the decoration will show an
36+
* error icon and a message and if the expression is valid then the decoration
37+
* will be hidden.
38+
*
39+
* @param regex The regular expression to be validated.
40+
* @param targetDecoration The control decoration that will show the result of
41+
* the validation.
42+
*/
43+
public static void validateRegex(String regex, ControlDecoration targetDecoration) {
44+
String errorMessage = getValidationError(regex);
45+
if (errorMessage.isEmpty()) {
46+
targetDecoration.hide();
47+
return;
48+
49+
}
50+
51+
Image decorationImage = FieldDecorationRegistry.getDefault()
52+
.getFieldDecoration(FieldDecorationRegistry.DEC_ERROR).getImage();
53+
targetDecoration.setImage(decorationImage);
54+
targetDecoration.setDescriptionText(errorMessage);
55+
targetDecoration.show();
56+
}
57+
58+
/**
59+
* Validate a regular expression.
60+
*
61+
* @return The appropriate error message if the regex is invalid or an empty
62+
* string if the regex is valid.
63+
*/
64+
private static String getValidationError(String regex) {
65+
try {
66+
Pattern.compile(regex);
67+
return ""; //$NON-NLS-1$
68+
} catch (PatternSyntaxException e) {
69+
String message = e.getLocalizedMessage();
70+
71+
// Only preserve the first line of the original error message.
72+
int i = 0;
73+
while (i < message.length() && "\n\r".indexOf(message.charAt(i)) == -1) { //$NON-NLS-1$
74+
i++;
75+
}
76+
77+
return message.substring(0, i);
78+
}
79+
}
80+
81+
}

0 commit comments

Comments
 (0)