/*
* Created on 02.12.2008
*/
package org.jdesktop.swingx.demos.search;
import java.awt.Component;
import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import javax.swing.JLabel;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.SearchPredicate;
import org.jdesktop.swingx.painter.Painter;
import org.jdesktop.swingx.renderer.PainterAware;
import org.jdesktop.swingx.renderer.WrappingIconPanel;
/**
* MatchingHighlighter which marks clipped match as well. This is a hack, should
* be supported in super.
*
* @author Jeanette Winzenburg
* @author Thorsten Klimpel
*/
public class XMatchingTextHighlighter extends MatchingTextHighlighter {
// copy of private super field
Rectangle myTextR;
public XMatchingTextHighlighter() {
this(null);
}
public XMatchingTextHighlighter(Painter<JLabel> painter) {
super(painter);
}
@Override
protected List<Rectangle> createHighlightAreas(String fullText,
String clippedText, FontMetrics fm, int xOffset, int yOffset,
int height) {
List<Rectangle> areas = super.createHighlightAreas( fullText,
clippedText, fm, xOffset, yOffset, height );
// Look for one (or more) 'ellipsed' matches of many matches. Goal is to
// highlight characters in visible AND clipped (ellipsis) text.
if ( !fullText.equals( clippedText ) )
{
SearchPredicate predicate = (SearchPredicate) getHighlightPredicate();
int matchesInFullText = 0;
Matcher matcher = predicate.getPattern().matcher( fullText );
while ( matcher.find() )
matchesInFullText++;
//The areas of highlighted regions could be coalesced, so the
// count ( areas.size() ) could be too low. So matching here again:
int matchesInClippedText = 0;
matcher = predicate.getPattern().matcher( clippedText );
while ( matcher.find() )
matchesInClippedText++;
if ( matchesInFullText > matchesInClippedText )
{// happens if at least one match is under the ellipsis
if ( areas.isEmpty() )
areas = new ArrayList<Rectangle>();
// here we rely on the given text to not contain the ellipsis
// PENDING JW: should be supported in super
int beginOfEllipsis = fm.stringWidth( clippedText ) + xOffset;
areas.add( new Rectangle( beginOfEllipsis, yOffset,
fm.stringWidth( "..." ), height ) );// hopefully no one ever changes
//the 3 points to a real "\u2026" ellipsis ;-) I think as long as we
//are explicitly removing the last 3 characters of the String in the
//super-class we can 'add' them here again.
}
}
return areas;
}
/**
* Overridden to copy super's private field.
*/
@Override
protected int calculateXOffset(JLabel component, Rectangle viewR,
Rectangle textR, Rectangle iconR, int iconTextGap) {
myTextR = textR;
return super.calculateXOffset(component, viewR, textR, iconR,
iconTextGap);
}
@Override
protected Component doHighlight(Component component,
ComponentAdapter adapter) {
if (isLabelCompatible(component))
return super.doHighlight(component, adapter);
((PainterAware) component).setPainter(getPainter());
return component;
}
@Override
protected boolean canHighlight(Component component, ComponentAdapter adapter) {
return // (component instanceof JLabel ||
// (component instanceof WrappingIconPanel)
// &&
component instanceof PainterAware && getPainter() != null
&& getHighlightPredicate() instanceof SearchPredicate;
}
protected boolean isLabelCompatible(Component component) {
return component instanceof JLabel
|| (component instanceof WrappingIconPanel && ((WrappingIconPanel) component)
.getComponent() instanceof JLabel);
}
}