Skip to content

Commit

Permalink
repairs the quick search and highlighting
Browse files Browse the repository at this point in the history
 - implemented all-filter and made it the default
 - fixed search highlighting for the diff view's msg and author columns
 - fixed search highlighting in selected summary entries
 - highlighting works now in tooltips too
  • Loading branch information
mbien committed Mar 4, 2024
1 parent 637433e commit 7cf9a42
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ MSG_RevisionNodeChildren.Loading=Loading...
MSG_SearchHistoryPanel.GettingMoreRevisions=Getting more revisions
filterLabel.text=Fi&lter:
containsLabel=&contains
Filter.All=No Filter
Filter.All=All
Filter.Message=Message
Filter.User=Author
Filter.Commit=Revision
Expand Down
20 changes: 13 additions & 7 deletions ide/git/src/org/netbeans/modules/git/ui/history/DiffTreeTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ private void setupColumns() {
setPropertyColumnDescription(RevisionNode.COLUMN_NAME_DATE, loc.getString("LBL_DiffTree_Column_Time_Desc"));
setPropertyColumnDescription(RevisionNode.COLUMN_NAME_USERNAME, loc.getString("LBL_DiffTree_Column_Username_Desc"));
setPropertyColumnDescription(RevisionNode.COLUMN_NAME_MESSAGE, loc.getString("LBL_DiffTree_Column_Message_Desc"));
TableColumn msgColumn = getOutline().getColumn(loc.getString("LBL_DiffTree_Column_Message"));
msgColumn.setCellRenderer(new MessageRenderer(getOutline().getCellRenderer(0, msgColumn.getModelIndex())));
TableColumnModel model = getOutline().getColumnModel();
if (model instanceof ETableColumnModel) {
((ETableColumnModel) model).setColumnHidden(model.getColumn(1), true);
}
setDefaultColumnSizes();
TableColumn column = getOutline().getColumn(loc.getString("LBL_DiffTree_Column_Message"));
column.setCellRenderer(new MessageRenderer(getOutline().getDefaultRenderer(String.class)));
}

private void setDefaultColumnSizes() {
Expand Down Expand Up @@ -188,13 +188,19 @@ public Component getTableCellRendererComponent (JTable table, Object value, bool
String tooltip = tooltips.get(val);
if (tooltip == null) {
tooltip = val.replace("\r\n", "\n").replace("\r", "\n"); //NOI18N
try {
tooltip = XMLUtil.toElementContent(tooltip);
} catch (CharConversionException e1) {
Logger.getLogger(DiffTreeTable.class.getName()).log(Level.INFO, "Can not HTML escape: ", tooltip); //NOI18N
boolean highlighterActive = tooltip.startsWith("<html>");
if (!highlighterActive) {
try {
tooltip = XMLUtil.toElementContent(tooltip);
} catch (CharConversionException e1) {
Logger.getLogger(DiffTreeTable.class.getName()).log(Level.INFO, "Can not HTML escape: ", tooltip); //NOI18N
}
}
if (tooltip.contains("\n")) {
tooltip = "<html><body><p>" + tooltip.replace("\n", "<br>") + "</p></body></html>"; //NOI18N
tooltip = tooltip.replace("\n", "<br>");
if (!highlighterActive) {
tooltip = "<html><body><p>" + tooltip + "</p></body></html>"; //NOI18N
}
c.setToolTipText(tooltip);
}
tooltips.put(val, tooltip);
Expand Down
26 changes: 16 additions & 10 deletions ide/git/src/org/netbeans/modules/git/ui/history/RevisionNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.awt.Rectangle;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
Expand Down Expand Up @@ -140,12 +141,12 @@ public Action[] getActions (boolean context) {
}

private void initProperties() {
AttributeSet searchHiliteAttrs = ((FontColorSettings) MimeLookup.getLookup(MimePath.get("text/x-java")).lookup(FontColorSettings.class)).getFontColors("highlight-search"); //NOI18N
Color c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Background);
AttributeSet searchHighlightAttrs = ((FontColorSettings) MimeLookup.getLookup(MimePath.get("text/x-java")).lookup(FontColorSettings.class)).getFontColors("highlight-search"); //NOI18N
Color c = (Color) searchHighlightAttrs.getAttribute(StyleConstants.Background);
if (c != null) {
bgColor = getColorString(c);
}
c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Foreground);
c = (Color) searchHighlightAttrs.getAttribute(StyleConstants.Foreground);
if (c != null) {
fgColor = getColorString(c);
}
Expand Down Expand Up @@ -192,17 +193,22 @@ public PropertyEditor getPropertyEditor() {
}
}

private static String highlight (String author, String needle, String bgColor, String fgColor) {
private static String escape(String text) {
return text.replace("<", "&lt;");
}

private static String highlight(String text, String needle, String bgColor, String fgColor) {
if (fgColor != null && bgColor != null) {
int idx = author.toLowerCase().indexOf(needle);
int idx = text.toLowerCase(Locale.ROOT).indexOf(needle);
if (idx != -1) {
return new StringBuilder("<html><body>").append(author.substring(0, idx)) //NOI18N
.append("<span style=\"background-color: ").append(bgColor).append("; color: ").append(fgColor).append(";\">") //NOI18N
.append(author.substring(idx, idx + needle.length())).append("</span>") //NOI18N
.append(author.substring(idx + needle.length())).append("</body></html>").toString(); //NOI18N
return new StringBuilder(256)
.append("<html><body><nobr>").append(escape(text.substring(0, idx))) //NOI18N
.append("<span style=\"background-color: ").append(bgColor).append("; color: ").append(fgColor).append(";\">") //NOI18N
.append(escape(text.substring(idx, idx + needle.length()))).append("</span>") //NOI18N
.append(escape(text.substring(idx + needle.length()))).append("</nobr></body></html>").toString(); //NOI18N
}
}
return author;
return text;
}

private class UsernameProperty extends CommitNodeProperty {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BoxLayout;
Expand All @@ -61,6 +62,7 @@
import javax.swing.UIManager;
import org.netbeans.libs.git.GitBranch;
import org.netbeans.libs.git.GitException;
import org.netbeans.libs.git.GitRevisionInfo;
import org.netbeans.libs.git.GitTag;
import org.netbeans.modules.git.Git;
import org.netbeans.modules.git.GitModuleConfig;
Expand All @@ -73,6 +75,8 @@
import org.netbeans.modules.versioning.util.VCSKenaiAccessor;
import org.openide.util.WeakListeners;

import static java.util.Locale.ROOT;

/**
* Contains all components of the Search History panel.
*
Expand All @@ -98,6 +102,7 @@ class SearchHistoryPanel extends javax.swing.JPanel implements ExplorerManager.P
private AbstractAction nextAction;
private AbstractAction prevAction;
private final File repository;
private final ExplorerManager explorerManager;

private static final Icon ICON_COLLAPSED = UIManager.getIcon("Tree.collapsedIcon"); //NOI18N
private static final Icon ICON_EXPANDED = UIManager.getIcon("Tree.expandedIcon"); //NOI18N
Expand All @@ -115,13 +120,15 @@ class SearchHistoryPanel extends javax.swing.JPanel implements ExplorerManager.P
private final PropertyChangeListener list;

enum FilterKind {

ALL(null, NbBundle.getMessage(SearchHistoryPanel.class, "Filter.All")), //NOI18N
MESSAGE(SearchHighlight.Kind.MESSAGE, NbBundle.getMessage(SearchHistoryPanel.class, "Filter.Message")), //NOI18N
USER(SearchHighlight.Kind.AUTHOR, NbBundle.getMessage(SearchHistoryPanel.class, "Filter.User")), //NOI18N
ID(SearchHighlight.Kind.REVISION, NbBundle.getMessage(SearchHistoryPanel.class, "Filter.Commit")), //NOI18N
FILE(SearchHighlight.Kind.FILE, NbBundle.getMessage(SearchHistoryPanel.class, "Filter.File")); //NOI18N
private String label;
private SearchHighlight.Kind kind;

private final String label;
private final SearchHighlight.Kind kind;

FilterKind (SearchHighlight.Kind kind, String label) {
this.kind = kind;
Expand Down Expand Up @@ -258,7 +265,6 @@ public Component getListCellRendererComponent (JList<?> list, Object value, int
refreshBranchFilterModel();
}

private ExplorerManager explorerManager;

@Override
public void propertyChange(PropertyChangeEvent evt) {
Expand Down Expand Up @@ -326,6 +332,9 @@ final void refreshComponents(boolean refreshResults) {
updateActions();
fileInfoCheckBox.setVisible(tbSummary.isSelected());
layoutButton.setVisible(!tbSummary.isSelected());
bPrev.setVisible(!tbSummary.isSelected());
bNext.setVisible(!tbSummary.isSelected());
jSeparator3.setVisible(!tbSummary.isSelected());

searchCriteriaPanel.setVisible(criteriaVisible);
bSearch.setVisible(criteriaVisible);
Expand Down Expand Up @@ -592,16 +601,11 @@ private void expandCriteriaButtonActionPerformed (java.awt.event.ActionEvent evt
}//GEN-LAST:event_expandCriteriaButtonActionPerformed

private void cmbFilterKindActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmbFilterKindActionPerformed
boolean filterCritVisible = cmbFilterKind.getSelectedItem() != FilterKind.ALL;
lblFilterContains.setVisible(filterCritVisible);
txtFilter.setVisible(filterCritVisible);
if (filterCritVisible) {
EventQueue.invokeLater(() -> {
if (!cmbFilterKind.isPopupVisible()) {
txtFilter.requestFocusInWindow();
}
});
}
EventQueue.invokeLater(() -> {
if (!cmbFilterKind.isPopupVisible()) {
txtFilter.requestFocusInWindow();
}
});
if (filterTimer != null && !txtFilter.getText().isBlank()) {
filterTimer.restart();
}
Expand Down Expand Up @@ -755,13 +759,17 @@ void getMoreRevisions (PropertyChangeListener callback, int count) {
NbBundle.getMessage(SearchHistoryPanel.class, "MSG_SearchHistoryPanel.GettingMoreRevisions")); //NOI18N
}

Collection<SearchHighlight> getSearchHighlights () {
String filterText = txtFilter.getText().trim();
Collection<SearchHighlight> getSearchHighlights() {
String filterText = txtFilter.getText().strip();
Object selectedFilterKind = cmbFilterKind.getSelectedItem();
if (selectedFilterKind == FilterKind.ALL || filterText.isEmpty() || !(selectedFilterKind instanceof FilterKind)) {
if (filterText.isEmpty() || !(selectedFilterKind instanceof FilterKind)) {
return Collections.emptyList();
} else if (selectedFilterKind == FilterKind.ALL) {
return List.of(new SearchHighlight(SearchHighlight.Kind.AUTHOR, filterText),
new SearchHighlight(SearchHighlight.Kind.MESSAGE, filterText),
new SearchHighlight(SearchHighlight.Kind.REVISION, filterText));
} else {
return Set.of(new SearchHighlight(((FilterKind) selectedFilterKind).kind, filterText));
return List.of(new SearchHighlight(((FilterKind) selectedFilterKind).kind, filterText));
}
}

Expand All @@ -777,41 +785,37 @@ private void initializeFilter () {
txtFilter.getDocument().addDocumentListener(this);
}

private List<RepositoryRevision> filter (List<RepositoryRevision> results) {
List<RepositoryRevision> newResults = new ArrayList<>(results.size());
for (RepositoryRevision rev : results) {
if (applyFilter(rev)) {
newResults.add(rev);
}
}
return newResults;
private List<RepositoryRevision> filter(List<RepositoryRevision> results) {
FilterKind kind = (FilterKind)cmbFilterKind.getSelectedItem();
String filter = txtFilter.getText().strip().toLowerCase(ROOT);
return results.stream()
.filter(rev -> applyFilter(rev, kind, filter))
.collect(Collectors.toList());
}

boolean applyFilter (RepositoryRevision rev) {
boolean visible = true;
String filterText = txtFilter.getText().strip().toLowerCase();
Object selectedFilterKind = cmbFilterKind.getSelectedItem();
if (selectedFilterKind != FilterKind.ALL && !filterText.isEmpty()) {
if (selectedFilterKind == FilterKind.MESSAGE) {
visible = rev.getLog().getFullMessage().toLowerCase().contains(filterText);
} else if (selectedFilterKind == FilterKind.USER) {
visible = rev.getLog().getAuthor().toString().toLowerCase().contains(filterText);
} else if (selectedFilterKind == FilterKind.ID) {
visible = rev.getLog().getRevision().contains(filterText)
|| contains(rev.getBranches(), filterText)
|| contains(rev.getTags(), filterText);
}
}
Object selectedBranchFilter = currentBranchFilter;
if (visible && selectedBranchFilter instanceof GitBranch) {
visible = rev.getLog().getBranches().containsKey(((GitBranch) currentBranchFilter).getName());
boolean applyFilter(RepositoryRevision rev) {
return applyFilter(rev, (FilterKind)cmbFilterKind.getSelectedItem(), txtFilter.getText().strip().toLowerCase(ROOT));
}

private boolean applyFilter(RepositoryRevision rev, FilterKind kind, String text) {
GitRevisionInfo log = rev.getLog();
boolean visible = text.isEmpty()
|| (allOrEquals(kind, FilterKind.MESSAGE) && log.getFullMessage().toLowerCase(ROOT).contains(text))
|| (allOrEquals(kind, FilterKind.USER) && log.getAuthor().toString().toLowerCase(ROOT).contains(text))
|| (allOrEquals(kind, FilterKind.ID) && (log.getRevision().contains(text) || contains(rev.getBranches(), text) || contains(rev.getTags(), text)));
if (visible && currentBranchFilter instanceof GitBranch) {
visible = log.getBranches().containsKey(((GitBranch) currentBranchFilter).getName());
}
return visible;
}

private static boolean allOrEquals(FilterKind toCheck, FilterKind required) {
return toCheck == FilterKind.ALL || toCheck == required;
}

private static boolean contains (GitBranch[] items, String needle) {
for (GitBranch item : items) {
if (item.getName() != GitBranch.NO_BRANCH && item.getName().toLowerCase().contains(needle)) {
if (item.getName() != GitBranch.NO_BRANCH && item.getName().toLowerCase(ROOT).contains(needle)) {
return true;
}
}
Expand All @@ -820,7 +824,7 @@ private static boolean contains (GitBranch[] items, String needle) {

private static boolean contains (GitTag[] items, String needle) {
for (GitTag item : items) {
if (item.getTagName().toLowerCase().contains(needle)) {
if (item.getTagName().toLowerCase(ROOT).contains(needle)) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,25 +540,19 @@ private void addCommitMessage (JTextPane pane, RevisionItem item, boolean select
linkerSupport.add(messageTooltip, id);
}

if (!selected) {
for (SearchHighlight highlight : highlights) {
if (highlight.getKind() == SearchHighlight.Kind.MESSAGE) {
String highlightMessage = highlight.getSearchText();
int idx = commitMessage.toLowerCase().indexOf(highlightMessage);
if (idx == -1) {
if (nlc > 0 && !item.messageExpanded && entry.getMessage().toLowerCase().contains(highlightMessage)) {
sd.setCharacterAttributes(doclen, sd.getLength(), hiliteStyle, false);
}
} else {
sd.setCharacterAttributes(doclen - msglen + idx, highlightMessage.length(), hiliteStyle, false);
for (SearchHighlight highlight : highlights) {
if (highlight.getKind() == SearchHighlight.Kind.MESSAGE) {
String highlightMessage = highlight.getSearchText();
int idx = commitMessage.toLowerCase().indexOf(highlightMessage);
if (idx == -1) {
if (nlc > 0 && !item.messageExpanded && entry.getMessage().toLowerCase().contains(highlightMessage)) {
sd.setCharacterAttributes(doclen, sd.getLength(), hiliteStyle, false);
}
} else {
sd.setCharacterAttributes(doclen - msglen + idx, highlightMessage.length(), hiliteStyle, false);
}
}
}

if (selected) {
sd.setCharacterAttributes(0, Integer.MAX_VALUE, style, false);
}
}

private Style createNormalStyle (JTextPane textPane) {
Expand Down

0 comments on commit 7cf9a42

Please sign in to comment.