Skip to content

Commit 0474b01

Browse files
authored
Add filtering support for duplicate files in nested projects (eclipse-platform#144)
* Add filtering support for duplicate files in nested projects - add filter to File Search to remove duplicate file entries that are attributed to different projects in a nested project scenario - fixes eclipse-platform#143
1 parent 5bfa15d commit 0474b01

File tree

7 files changed

+293
-25
lines changed

7 files changed

+293
-25
lines changed

org.eclipse.search/search/org/eclipse/search/internal/ui/SearchMessages.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2017 IBM Corporation and others.
2+
* Copyright (c) 2000, 2023 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,7 @@
1313
* Christian Walther (Indel AG) - Bug 399094: Add whole word option to file search
1414
* Marco Descher <[email protected]> - Open Search dialog with previous page instead of using the current selection to detect the page - http://bugs.eclipse.org/33710
1515
* Lucas Bullen (Red Hat Inc.) - [Bug 526453] disambiguate "Selected Resources"
16+
* Red Hat Inc. - add support for filtering innermost project files for file search
1617
*******************************************************************************/
1718
package org.eclipse.search.internal.ui;
1819

@@ -127,6 +128,9 @@ private SearchMessages() {
127128
public static String SearchPage_regularExpression;
128129
public static String SearchPage_wholeWord;
129130
public static String TextSearchEngine_statusMessage;
131+
public static String TextSearchInnermostProjectFilter_action_label;
132+
public static String TextSearchInnermostProjectFilter_name;
133+
public static String TextSearchInnermostProjectFilter_description;
130134
public static String TextSearchPage_replace_querycreationproblem_message;
131135
public static String TextSearchPage_replace_runproblem_message;
132136
public static String TextSearchPage_searchIn_label;
@@ -172,6 +176,8 @@ private SearchMessages() {
172176
public static String FileSearchPage_sort_by_label;
173177
public static String FileSearchPage_limited_format_files;
174178
public static String FileSearchPage_limited_format_matches;
179+
public static String FileSearchPage_filtered_message;
180+
public static String FileSearchPage_filteredWithCount_message;
175181
public static String WorkspaceScope;
176182
public static String ScopePart_group_text;
177183
public static String ScopePart_selectedResourcesScope_text;

org.eclipse.search/search/org/eclipse/search/internal/ui/SearchMessages.properties

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
###############################################################################
2-
# Copyright (c) 2000, 2017 IBM Corporation and others.
2+
# Copyright (c) 2000, 2023 IBM Corporation and others.
33
#
44
# This program and the accompanying materials
55
# are made available under the terms of the Eclipse Public License 2.0
@@ -97,6 +97,9 @@ SearchPage_wholeWord= Who&le word
9797

9898
TextSearchEngine_statusMessage= Problems encountered during text search.
9999

100+
TextSearchInnermostProjectFilter_action_label=Show only most &nested match
101+
TextSearchInnermostProjectFilter_name=Duplicate match from outer project
102+
TextSearchInnermostProjectFilter_description= For files in nested projects, don't show matches for duplicate file references that are owned by projects that aren't the innermost project.
100103
TextSearchPage_searchIn_label=Search In
101104
TextSearchPage_searchDerived_label=Deri&ved resources
102105
TextSearchPage_searchBinary_label=&Binary files
@@ -180,6 +183,8 @@ FileSearchPage_sort_by_label=Sort By
180183
FileSearchPage_limited_format_files={0} (showing {1} of {2} files)
181184
FileSearchPage_limited_format_matches={0} (showing {1} of {2} matches)
182185
FileSearchPage_open_file_dialog_title=Open File
186+
FileSearchPage_filtered_message={0} (Filtered)
187+
FileSearchPage_filteredWithCount_message={0} ({1} matches filtered from view)
183188

184189
WorkspaceScope= workspace
185190

org.eclipse.search/search/org/eclipse/search/internal/ui/text/FileSearchPage.java

Lines changed: 96 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2019 IBM Corporation and others.
2+
* Copyright (c) 2000, 2023 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,7 @@
1313
* Juerg Billeter, [email protected] - 47136 Search view should show match objects
1414
* Ulrich Etter, [email protected] - 47136 Search view should show match objects
1515
* Roman Fuchs, [email protected] - 47136 Search view should show match objects
16+
* Red Hat Inc. - add support for filtering files that are not from innermost nested project
1617
*******************************************************************************/
1718
package org.eclipse.search.internal.ui.text;
1819

@@ -27,11 +28,15 @@
2728
import org.eclipse.swt.dnd.DND;
2829
import org.eclipse.swt.dnd.Transfer;
2930
import org.eclipse.swt.widgets.Display;
31+
import org.eclipse.swt.widgets.Item;
32+
import org.eclipse.swt.widgets.Table;
33+
import org.eclipse.swt.widgets.Tree;
3034

3135
import org.eclipse.core.runtime.IAdaptable;
3236

3337
import org.eclipse.core.resources.IContainer;
3438
import org.eclipse.core.resources.IFile;
39+
import org.eclipse.core.resources.IResource;
3540

3641
import org.eclipse.core.filebuffers.FileBuffers;
3742
import org.eclipse.core.filebuffers.ITextFileBuffer;
@@ -44,7 +49,6 @@
4449
import org.eclipse.jface.viewers.ILabelProvider;
4550
import org.eclipse.jface.viewers.ISelection;
4651
import org.eclipse.jface.viewers.ISelectionProvider;
47-
import org.eclipse.jface.viewers.IStructuredContentProvider;
4852
import org.eclipse.jface.viewers.IStructuredSelection;
4953
import org.eclipse.jface.viewers.ITreeContentProvider;
5054
import org.eclipse.jface.viewers.ITreeViewerListener;
@@ -74,6 +78,7 @@
7478
import org.eclipse.search.internal.ui.SearchMessages;
7579
import org.eclipse.search.ui.IContextMenuConstants;
7680
import org.eclipse.search.ui.ISearchResultViewPart;
81+
import org.eclipse.search.ui.NewSearchUI;
7782
import org.eclipse.search.ui.text.AbstractTextSearchResult;
7883
import org.eclipse.search.ui.text.AbstractTextSearchViewPage;
7984
import org.eclipse.search.ui.text.Match;
@@ -423,38 +428,113 @@ public <T> T getAdapter(Class<T> adapter) {
423428
return null;
424429
}
425430

431+
private boolean isQueryRunning() {
432+
AbstractTextSearchResult result = getInput();
433+
if (result != null) {
434+
return NewSearchUI.isQueryRunning(result.getQuery());
435+
}
436+
return false;
437+
}
438+
426439
@Override
427440
public String getLabel() {
428441
String label= super.getLabel();
429442
StructuredViewer viewer= getViewer();
430-
if (viewer instanceof TableViewer) {
431-
TableViewer tv= (TableViewer) viewer;
432-
433-
AbstractTextSearchResult result= getInput();
434-
if (result != null) {
435-
int itemCount= ((IStructuredContentProvider) tv.getContentProvider()).getElements(getInput()).length;
443+
AbstractTextSearchResult result = getInput();
444+
String msg = label;
445+
if (result != null) {
446+
if (viewer instanceof TableViewer) {
447+
TableViewer tv = (TableViewer) viewer;
448+
449+
int itemCount = ((FileTableContentProvider) tv.getContentProvider())
450+
.getUnfilteredElements(getInput()).length;
436451
if (showLineMatches()) {
437452
int matchCount= getInput().getMatchCount();
438453
if (itemCount < matchCount) {
439-
return Messages.format(SearchMessages.FileSearchPage_limited_format_matches, new Object[]{label, Integer.valueOf(itemCount), Integer.valueOf(matchCount)});
454+
msg = Messages.format(SearchMessages.FileSearchPage_limited_format_matches,
455+
new Object[] { label, Integer.valueOf(itemCount), Integer.valueOf(matchCount) });
440456
}
441457
} else {
442458
int fileCount= getInput().getElements().length;
443459
if (itemCount < fileCount) {
444-
return Messages.format(SearchMessages.FileSearchPage_limited_format_files, new Object[]{label, Integer.valueOf(itemCount), Integer.valueOf(fileCount)});
460+
msg = Messages.format(SearchMessages.FileSearchPage_limited_format_files,
461+
new Object[] { label, Integer.valueOf(itemCount), Integer.valueOf(fileCount) });
445462
}
446463
}
464+
465+
}
466+
if (result.getActiveMatchFilters() != null && result.getActiveMatchFilters().length > 0) {
467+
if (isQueryRunning()) {
468+
String message = SearchMessages.FileSearchPage_filtered_message;
469+
return Messages.format(message, new Object[] { msg });
470+
471+
} else {
472+
int filteredOut = result.getMatchCount() - getFilteredMatchCount();
473+
String message = SearchMessages.FileSearchPage_filteredWithCount_message;
474+
return Messages.format(message, new Object[] { msg, String.valueOf(filteredOut) });
475+
}
447476
}
448477
}
449-
return label;
478+
return msg;
479+
}
480+
481+
private int getFilteredMatchCount() {
482+
StructuredViewer viewer = getViewer();
483+
if (viewer instanceof TreeViewer) {
484+
ITreeContentProvider tp = (ITreeContentProvider) viewer.getContentProvider();
485+
return getMatchCount(tp, getRootElements((TreeViewer) getViewer()));
486+
} else {
487+
return getMatchCount((TableViewer) viewer);
488+
}
489+
}
490+
491+
private Object[] getRootElements(TreeViewer viewer) {
492+
Tree t = viewer.getTree();
493+
Item[] roots = t.getItems();
494+
Object[] elements = new Object[roots.length];
495+
for (int i = 0; i < elements.length; i++) {
496+
elements[i] = roots[i].getData();
497+
}
498+
return elements;
499+
}
500+
501+
private Object[] getRootElements(TableViewer viewer) {
502+
Table t = viewer.getTable();
503+
Item[] roots = t.getItems();
504+
Object[] elements = new Object[roots.length];
505+
for (int i = 0; i < elements.length; i++) {
506+
elements[i] = roots[i].getData();
507+
}
508+
return elements;
509+
}
510+
511+
private int getMatchCount(ITreeContentProvider cp, Object[] elements) {
512+
int count = 0;
513+
for (Object element : elements) {
514+
count += getDisplayedMatchCount(element);
515+
Object[] children = cp.getChildren(element);
516+
count += getMatchCount(cp, children);
517+
}
518+
return count;
519+
}
520+
521+
private int getMatchCount(TableViewer viewer) {
522+
int count = 0;
523+
for (Object element : getRootElements(viewer)) {
524+
count += getDisplayedMatchCount(element);
525+
}
526+
return count;
450527
}
451528

452529
@Override
453530
public int getDisplayedMatchCount(Object element) {
454531
if (showLineMatches()) {
455532
if (element instanceof LineElement) {
456533
LineElement lineEntry= (LineElement) element;
457-
return lineEntry.getNumberOfMatches(getInput());
534+
IResource res = lineEntry.getParent();
535+
if (super.getDisplayedMatchCount(res) > 0) {
536+
return lineEntry.getNumberOfMatches(getInput());
537+
}
458538
}
459539
return 0;
460540
}
@@ -466,7 +546,10 @@ public Match[] getDisplayedMatches(Object element) {
466546
if (showLineMatches()) {
467547
if (element instanceof LineElement) {
468548
LineElement lineEntry= (LineElement) element;
469-
return lineEntry.getMatches(getInput());
549+
IResource res = lineEntry.getParent();
550+
if (super.getDisplayedMatchCount(res) > 0) {
551+
return lineEntry.getMatches(getInput());
552+
}
470553
}
471554
return new Match[0];
472555
}

org.eclipse.search/search/org/eclipse/search/internal/ui/text/FileSearchResult.java

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2008 IBM Corporation and others.
2+
* Copyright (c) 2000, 2023 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,9 +10,13 @@
1010
*
1111
* Contributors:
1212
* IBM Corporation - initial API and implementation
13+
* Red Hat Inc. - add support for filtering files from innermost nested projects
1314
*******************************************************************************/
1415
package org.eclipse.search.internal.ui.text;
1516

17+
import java.util.HashSet;
18+
import java.util.StringTokenizer;
19+
1620
import org.eclipse.core.resources.IFile;
1721

1822
import org.eclipse.jface.resource.ImageDescriptor;
@@ -21,12 +25,14 @@
2125
import org.eclipse.ui.IEditorPart;
2226
import org.eclipse.ui.IFileEditorInput;
2327

28+
import org.eclipse.search.internal.ui.SearchPlugin;
2429
import org.eclipse.search.internal.ui.SearchPluginImages;
2530
import org.eclipse.search.ui.ISearchQuery;
2631
import org.eclipse.search.ui.text.AbstractTextSearchResult;
2732
import org.eclipse.search.ui.text.IEditorMatchAdapter;
2833
import org.eclipse.search.ui.text.IFileMatchAdapter;
2934
import org.eclipse.search.ui.text.Match;
35+
import org.eclipse.search.ui.text.MatchFilter;
3036

3137
public class FileSearchResult extends AbstractTextSearchResult implements IEditorMatchAdapter, IFileMatchAdapter {
3238
private final Match[] EMPTY_ARR= new Match[0];
@@ -35,20 +41,88 @@ public class FileSearchResult extends AbstractTextSearchResult implements IEdito
3541

3642
public FileSearchResult(FileSearchQuery job) {
3743
fQuery= job;
44+
setActiveMatchFilters(getLastUsedFilters());
3845
}
46+
3947
@Override
4048
public ImageDescriptor getImageDescriptor() {
4149
return SearchPluginImages.DESC_OBJ_TSEARCH_DPDN;
4250
}
51+
4352
@Override
4453
public String getLabel() {
4554
return fQuery.getResultLabel(getMatchCount());
4655
}
56+
4757
@Override
4858
public String getTooltip() {
4959
return getLabel();
5060
}
5161

62+
private static MatchFilter INNERMOST_PROJECT = new OuterProjectFileFilter();
63+
private static MatchFilter[] ALL_MATCH_FILTERS = new MatchFilter[] { INNERMOST_PROJECT };
64+
private static final String SETTINGS_LAST_USED_FILTERS = "filters_last_used"; //$NON-NLS-1$
65+
66+
@Override
67+
public MatchFilter[] getAllMatchFilters() {
68+
return ALL_MATCH_FILTERS;
69+
}
70+
71+
@Override
72+
public synchronized void setActiveMatchFilters(MatchFilter[] filters) {
73+
// TODO Auto-generated method stub
74+
super.setActiveMatchFilters(filters);
75+
setLastUsedFilters(filters);
76+
}
77+
78+
@Override
79+
public synchronized MatchFilter[] getActiveMatchFilters() {
80+
// TODO Auto-generated method stub
81+
return super.getActiveMatchFilters();
82+
}
83+
84+
public static MatchFilter[] getLastUsedFilters() {
85+
String string = SearchPlugin.getDefault().getDialogSettings().get(SETTINGS_LAST_USED_FILTERS);
86+
if (string != null) {
87+
return decodeFiltersString(string);
88+
}
89+
return new MatchFilter[0];
90+
}
91+
92+
public static void setLastUsedFilters(MatchFilter[] filters) {
93+
String encoded = encodeFilters(filters);
94+
SearchPlugin.getDefault().getDialogSettings().put(SETTINGS_LAST_USED_FILTERS, encoded);
95+
}
96+
97+
private static String encodeFilters(MatchFilter[] enabledFilters) {
98+
StringBuilder buf = new StringBuilder();
99+
for (MatchFilter matchFilter : enabledFilters) {
100+
buf.append(matchFilter.getID());
101+
buf.append(';');
102+
}
103+
return buf.toString();
104+
}
105+
106+
private static MatchFilter[] decodeFiltersString(String encodedString) {
107+
StringTokenizer tokenizer = new StringTokenizer(encodedString, String.valueOf(';'));
108+
HashSet<MatchFilter> result = new HashSet<>();
109+
while (tokenizer.hasMoreTokens()) {
110+
MatchFilter curr = findMatchFilter(tokenizer.nextToken());
111+
if (curr != null) {
112+
result.add(curr);
113+
}
114+
}
115+
return result.toArray(new MatchFilter[result.size()]);
116+
}
117+
118+
private static MatchFilter findMatchFilter(String id) {
119+
for (MatchFilter matchFilter : ALL_MATCH_FILTERS) {
120+
if (matchFilter.getID().equals(id))
121+
return matchFilter;
122+
}
123+
return null;
124+
}
125+
52126
@Override
53127
public Match[] computeContainedMatches(AbstractTextSearchResult result, IFile file) {
54128
return getMatches(file);

0 commit comments

Comments
 (0)