/*
* Created on Mar 8, 2004
*
* To change the template for this generated file go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
package com.limegroup.gnutella.gui.search;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.limegroup.gnutella.MediaType;
import com.limegroup.gnutella.browser.ExternalControl;
import com.limegroup.gnutella.browser.MagnetOptions;
import com.limegroup.gnutella.gui.GUIMediator;
import com.limegroup.gnutella.gui.MessageService;
import com.limegroup.gnutella.gui.MultiLineLabel;
import com.limegroup.gnutella.gui.download.DownloaderUtils;
import com.limegroup.gnutella.util.ProcessingQueue;
import com.limegroup.gnutella.util.StringUtils;
/**
*
* This singleton class listens to window activated events and parses the clipboard to see
* if a magnet uri is present. If it is it asks the user whether to download the file.
*/
public class MagnetClipboardListener extends WindowAdapter {
private static final Log LOG = LogFactory.getLog(MagnetClipboardListener.class);
private static final MagnetClipboardListener instance = new MagnetClipboardListener();
//the system clipboard
private final Clipboard CLIPBOARD = Toolkit.getDefaultToolkit().getSystemClipboard();
//dummy clipboard content
private final StringSelection empty =new StringSelection("");
private volatile String copiedText;
/**
* a thread which parses the clipboard and launches magnet downloads.
*/
private final ProcessingQueue clipboardParser = new ProcessingQueue("clipboard parser");
private Runnable parser = new Runnable() {
public void run() {
parseAndLaunch();
}
};
/**
* @return true if no errors occurred. False if we should not try to
* parse the clipboard anymore.
*/
private void parseAndLaunch() {
Transferable data = null;
try{
//check if there's anything in the clipboard
data = CLIPBOARD.getContents(this);
}catch(IllegalStateException isx) {
//we can't use the clipboard, give up.
return;
}
//is there anything in the clipboard?
if (data==null)
return;
//then, check if the data in the clipboard is text
if (!data.isDataFlavorSupported(DataFlavor.stringFlavor))
return;
//next, extract the content into a string
String contents=null;
try{
contents = (String)data.getTransferData(DataFlavor.stringFlavor);
} catch (IOException iox) {
LOG.info("problem occured while trying to parse clipboard, do nothing",iox);
return;
} catch (UnsupportedFlavorException ufx) {
LOG.error("UnsupportedFlavor??",ufx);
return;
}
//could not extract the clipboard as text.
if (contents == null)
return;
String copied = copiedText;
if (copied != null && copied.equals(contents)) {
// it is the magnet we just created
return;
}
//check if the magnet is valid
final MagnetOptions[] opts = ExternalControl.parseMagnets(contents);
if (opts.length == 0)
return; //not a valid magnet link
//at this point we know we have a valid magnet link in the clipboard.
LOG.info("clipboard contains "+ contents);
//purge the clipboard at this point
purgeClipboard();
//get a nicer looking address from the magnet
//turns out magnets are very liberal.. so display the whole thing
final String address = contents;
final MagnetOptions[] downloadCandidates = extractDownloadableMagnets(opts);
// and fire off the download
Runnable r = new Runnable() {
public void run() {
if (downloadCandidates.length > 0
&& showStartDownloadsDialog(downloadCandidates)) {
for (int i = 0; i < downloadCandidates.length; i++) {
DownloaderUtils.createDownloader(downloadCandidates[i]);
}
}
boolean oneSearchStarted = false;
for (int i = 0; i < opts.length; i++) {
if (!opts[i].isDownloadable()
&& opts[i].isKeywordTopicOnly() && !oneSearchStarted) {
String query = StringUtils.createQueryString
(opts[i].getKeywordTopic());
SearchInformation info =
SearchInformation.createKeywordSearch
(query, null, MediaType.getAnyTypeMediaType());
if (SearchMediator.validateInfo(info)
== SearchMediator.QUERY_VALID) {
oneSearchStarted = true;
SearchMediator.triggerSearch(info);
}
}
}
GUIMediator.instance().setWindow(GUIMediator.SEARCH_INDEX);
}
};
SwingUtilities.invokeLater(r);
}
private MagnetClipboardListener() {
super();
}
public static MagnetClipboardListener getInstance() {
return instance;
}
/**
* Sets the text that is going to be copied to the clipboard from withing
* LimeWire, so that the listener can discern between our own copied magnet
* links and the ones pasted from the outside.
* @param text
*/
public void setCopiedText(String text) {
copiedText = text;
}
/**
* ask the clipboard parser to see if there is a magnet.
*/
public void windowActivated(WindowEvent e) {
clipboardParser.add(parser);
}
/**
* clears the clipboard from the current string
*/
private void purgeClipboard(){
try {
CLIPBOARD.setContents(empty, empty);
}catch(IllegalStateException isx) {
//do nothing
}
}
/**
* Extracts magnets that are not keyword topic only magnets
* @param magnets
* @return
*/
private MagnetOptions[] extractDownloadableMagnets(MagnetOptions[] magnets) {
ArrayList dls = new ArrayList(magnets.length);
for (int i = 0; i < magnets.length; i++) {
MagnetOptions magnet = magnets[i];
if (!magnet.isKeywordTopicOnly()) {
dls.add(magnets[i]);
}
}
// all magnets are downloadable, return original array
if (dls.size() == magnets.length) {
return magnets;
}
else {
return (MagnetOptions[])dls.toArray(new MagnetOptions[0]);
}
}
private boolean showStartDownloadsDialog(MagnetOptions[] opts) {
JList magnetList = new JList(opts);
magnetList.setCellRenderer(new MagnetOptionsListCellRenderer());
magnetList.setVisibleRowCount(Math.min(6, opts.length));
magnetList.setFixedCellWidth(400);
Object[] content = new Object[] {
new MultiLineLabel(GUIMediator.getStringResource
("DOWNLOAD_MAGNET_DIALOG_MESSAGE"), 400),
new JScrollPane(magnetList)
};
int response = JOptionPane.showConfirmDialog
(MessageService.getParentComponent(), content,
GUIMediator.getStringResource("MESSAGE_CAPTION"),
JOptionPane.YES_NO_OPTION);
return response == JOptionPane.YES_OPTION;
}
private class MagnetOptionsListCellRenderer extends DefaultListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
MagnetOptions magnet = (MagnetOptions)value;
String fileName = magnet.getDisplayName();
if (fileName == null) {
fileName = GUIMediator.getStringResource("NO_FILENAME_LABEL");
}
super.getListCellRendererComponent(list, fileName, index, false,
false);
setToolTipText("<html><table width=\"400\"><tr><td>"
+ magnet.toString()
+ "</td></tr></table></html>");
return this;
}
}
}