/*
* Created on 08.04.2008
*
*/
package org.jdesktop.swingx.demos.table;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import org.jdesktop.swingx.decorator.AbstractHighlighter;
import org.jdesktop.swingx.decorator.ComponentAdapter;
import org.jdesktop.swingx.decorator.CompoundHighlighter;
import org.jdesktop.swingx.decorator.HighlightPredicate;
import org.jdesktop.swingx.decorator.IconHighlighter;
import org.jdesktop.swingx.decorator.HighlightPredicate.NotHighlightPredicate;
import org.jdesktop.swingx.hyperlink.AbstractHyperlinkAction;
import org.jdesktop.swingx.hyperlink.HyperlinkAction;
import org.jdesktop.swingx.renderer.HyperlinkProvider;
import org.jdesktop.swingx.renderer.LabelProvider;
import org.jdesktop.swingx.renderer.StringValue;
import org.jdesktop.swingx.renderer.StringValues;
import org.jdesktop.swingxset.util.DemoUtils;
public class OscarRendering {
@SuppressWarnings("unused")
private static final Logger LOG = Logger.getLogger(OscarRendering.class
.getName());
//<snip> JXTable column properties
// Note: the custom column factory is a feature enhanced factory
// which allows column configuration based on column identifier
public static void configureColumnFactory(CustomColumnFactory factory,
Class<?> resourceBase) {
// set location to load resources from
factory.setBaseClass(resourceBase);
// mark the isWinner column as hidden
factory.addHiddenNames("winnerColumn");
// register a custom comparator
Comparator<OscarCandidate> comparator = new Comparator<OscarCandidate>() {
public int compare(OscarCandidate o1, OscarCandidate o2) {
String movie1 = o1.getMovieTitle();
String movie2 = o2.getMovieTitle();
if (movie1 == null) return -1;
if (movie2 == null) return 1;
return movie1.compareTo(movie2);
}
};
factory.addComparator("movieTitleColumn", comparator);
// add hints for column sizing
OscarCandidate prototype = new OscarCandidate("Special Effects and");
prototype.getPersons().add("some unusually name or");
prototype.setYear(20000);
prototype.setMovieTitle("And here we go again ... should ");
factory.addPrototypeValue("yearColumn", prototype.getYear());
factory.addPrototypeValue("categoryColumn", prototype.getCategory());
factory.addPrototypeValue("movieTitleColumn", prototype);
factory.addPrototypeValue("nomineesColumn", prototype.getPersons());
// register component providers per column identifier
factory.addComponentProvider("yearColumn", new LabelProvider(JLabel.CENTER));
factory.addComponentProvider("nomineesColumn", new LabelProvider(new ListStringValue()));
factory.addComponentProvider("movieTitleColumn",
new HyperlinkProvider(new OscarCandidateLinkAction(), OscarCandidate.class));
// Visual Decorators
// .... and more
// </snip>
// <snip> Highlighter and Renderer
// ToolTip for movie column
StringValue toolTip = new StringValue() {
public String getString(Object value) {
if (value instanceof OscarCandidate) {
return getURIText((OscarCandidate) value);
}
return "";
}
private String getURIText(OscarCandidate target) {
URI uri = target.getIMDBMovieURI();
if (uri == null) {
return "http://www.imdb.com/" + "\"" + target.getMovieTitle() + "\"";
}
return target.getIMDBMovieURI().toString();
}
};
ToolTipHighlighter movieToolTip = new ToolTipHighlighter();
movieToolTip.addStringValue(toolTip, "movieTitleColumn");
factory.addHighlighter("movieTitleColumn", movieToolTip);
// ToolTips for nominees column
Icon winnerIcon = DemoUtils.getResourceIcon(resourceBase, "winnerIcon");
Icon nomineeIcon = DemoUtils.getResourceIcon(resourceBase, "nomineeIcon");
// Icon and tool tip decorator for winners
IconHighlighter winner = new IconHighlighter(winnerIcon);
ToolTipHighlighter winnerToolTip = new ToolTipHighlighter();
winnerToolTip.addStringValue(new ListStringValue(true, "Winner!", "Winners: "), "nomineesColumn");
// Icon and tool tip decorators for nominees
IconHighlighter nominee = new IconHighlighter(nomineeIcon);
ToolTipHighlighter nomineeToolTip = new ToolTipHighlighter();
nomineeToolTip.addStringValue(new ListStringValue(true, "Nominee", "Nominees: "), "nomineesColumn");
// the predicate to decide which to use
HighlightPredicate winnerPredicate = new HighlightPredicate() {
public boolean isHighlighted(Component renderer,
ComponentAdapter adapter) {
int modelColumn = adapter.getColumnIndex("winnerColumn");
return ((Boolean) adapter.getValue(modelColumn)).booleanValue();
}
};
// compound per-predicate and add as column highlighter to the factory
factory.addHighlighter("nomineesColumn", new CompoundHighlighter(
new CompoundHighlighter(winnerPredicate, winner, winnerToolTip),
new CompoundHighlighter(new NotHighlightPredicate(winnerPredicate),
nominee, nomineeToolTip)));
// </snip>
}
//<snip> Highlighter and Renderer
// a custom link action to drive the hyperlink on the movie column
/**
* HyperlinkAction to open the info page related to the OscarCandiate.
* <p>
*
* The URI is created lazily before browing:
* <ul>
* <li>initially, the OscarCandidate only has properties movieTitle and year
* (of nomination)
* <li>first time around, this action's performed the uri of the info page
* is searched online (done in IMBDLink) and set as property to the
* OscarCandidate
* <li>if successful, the uri of the info page is set as target to the
* wrapped HyperlinkAction and its performed is messaged to browse its
* target
* </ul>
*/
public static class OscarCandidateLinkAction extends
AbstractHyperlinkAction<OscarCandidate> {
HyperlinkAction browse = HyperlinkAction.createHyperlinkAction(null,
java.awt.Desktop.Action.BROWSE);
@Override
protected void installTarget() {
setName(target == null ? null : target.getMovieTitle());
setVisited(target != null ? target.getIMDBMovieURI() != null
: false);
}
public void actionPerformed(ActionEvent e) {
if (target == null)
return;
try {
URI imdbURI = target.getIMDBMovieURI();
if (imdbURI == null) {
imdbURI = lookupURI(imdbURI);
}
if (imdbURI != null) {
// success: browse uri
browse.setTarget(imdbURI);
browse.actionPerformed(null);
} else {
showLookupFailure();
}
} catch (Exception ex) {
showConnectionError(ex);
}
}
// </snip>
/**
* Looks up the URI of the info page.
*/
private URI lookupURI(URI imdbURI) throws IOException,
URISyntaxException {
// lookup uri if not yet set
String imdbString = IMDBLink.getMovieURIString(target
.getMovieTitle(), target.getYear());
if (imdbString != null) {
imdbURI = new URI(imdbString);
target.setIMDBMovieURI(imdbURI);
}
return imdbURI;
}
private void showLookupFailure() {
JOptionPane.showMessageDialog(
null,
// PENDING: localized message
// PENDING: source panel/window
"Unable to locate IMDB URL for" + "\n"
+ target.getMovieTitle(), "IMDB Link",
JOptionPane.INFORMATION_MESSAGE);
}
private void showConnectionError(Exception ex) {
// PENDING JW: use JXErrorDialog!
ex.printStackTrace();
}
}
//----------------- not special to OscarRendering, but still missing in SwingX :-)
/**
*
*/
public static class ToolTipHighlighter extends AbstractHighlighter {
private List<StringValue> stringValues;
private List<Object> sourceColumns;
private String delimiter;
/**
* Adds a StringValue to use on the given sourceColumn.
*
* @param sv the StringValue to use.
* @param sourceColumn the column identifier of the column to use.
*/
public void addStringValue(StringValue sv, Object sourceColumn) {
if (stringValues == null) {
stringValues = new ArrayList<StringValue>();
sourceColumns = new ArrayList<Object>();
}
stringValues.add(sv);
sourceColumns.add(sourceColumn);
}
/**
* Sets the delimiter to use between StringValues.
*
* @param delimiter the delimiter to use between StringValues, if there are more than one.
*/
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
@Override
protected Component doHighlight(Component component,
ComponentAdapter adapter) {
String toolTip = getToolTipText(component, adapter);
// PENDING: treetableCellRenderer doesn't reset tooltip!
if (toolTip != null) {
((JComponent) component).setToolTipText(toolTip);
}
return component;
}
private String getToolTipText(Component component,
ComponentAdapter adapter) {
if ((stringValues == null) || stringValues.isEmpty()) return null;
String text = "";
for (int i = 0; i < stringValues.size(); i++) {
int modelIndex = adapter.getColumnIndex(sourceColumns.get(i));
if (modelIndex >= 0) {
text += stringValues.get(i).getString(adapter.getValue(modelIndex));
if ((i != stringValues.size() - 1) && !isEmpty(text)){
text += delimiter;
}
}
}
return isEmpty(text) ? null : text;
}
private boolean isEmpty(String text) {
return text.length() == 0;
}
/**
* Overridden to check for JComponent type.
*/
@Override
protected boolean canHighlight(Component component,
ComponentAdapter adapter) {
return component instanceof JComponent;
}
}
public static class ListStringValue implements StringValue {
boolean isToolTip;
String singleToolTipPrefix;
String multipleToolTipPrefix;
public ListStringValue() {
this(false, null, null);
}
public ListStringValue(boolean asToolTip, String singleItem, String multipleItems) {
this.isToolTip = asToolTip;
this.singleToolTipPrefix = singleItem;
this.multipleToolTipPrefix = multipleItems;
}
@SuppressWarnings("unchecked")
public String getString(Object value) {
if (value instanceof List) {
List<String> persons = (List<String>) value;
if (isToolTip) {
return getStringAsToolTip(persons);
}
return getStringAsContent(persons);
}
return StringValues.TO_STRING.getString(value);
}
private String getStringAsToolTip(List<String> persons) {
if (persons.size() > 1) {
StringBuffer winners = new StringBuffer("");
if (multipleToolTipPrefix != null) {
winners.append(multipleToolTipPrefix);
}
for (String person : persons) {
winners.append(person);
winners.append(", ");
}
winners = winners.delete(winners.lastIndexOf(","), winners.length());
return winners.toString();
}
return StringValues.TO_STRING.getString(singleToolTipPrefix);
}
private String getStringAsContent(List<String> persons) {
if (persons.isEmpty()) {
return "unknown";
}
if (persons.size() > 1) {
return persons.get(0) + " + more ...";
}
return persons.get(0);
}
}
}