package org.limewire.ui.swing.friends.chat; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.util.Collections; import java.util.Map; import javax.swing.JOptionPane; import javax.swing.event.HyperlinkEvent; import javax.swing.text.html.FormSubmitEvent; import org.limewire.core.api.download.DownloadAction; import org.limewire.core.api.download.DownloadItem; import org.limewire.core.api.download.DownloadState; import org.limewire.core.api.download.ResultDownloader; import org.limewire.core.api.download.DownloadException; import org.limewire.core.api.friend.FileMetaDataConverter; import org.limewire.core.api.search.SearchResult; import org.limewire.io.InvalidDataException; import org.limewire.logging.Log; import org.limewire.logging.LogFactory; import org.limewire.ui.swing.components.FocusJOptionPane; import org.limewire.ui.swing.util.I18n; import org.limewire.ui.swing.util.NativeLaunchUtils; import org.limewire.ui.swing.util.DownloadExceptionHandler; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; /** * HyperlinkListener for links to libraries, form submissions (file offers) * that come from chat. */ class ChatHyperlinkListener implements javax.swing.event.HyperlinkListener { private static final Log LOG = LogFactory.getLog(ChatHyperlinkListener.class); private Conversation conversation; private final ResultDownloader downloader; private final FileMetaDataConverter remoteFileItemFactory; private final Provider<DownloadExceptionHandler> downloadExceptionHandler; @Inject public ChatHyperlinkListener(@Assisted Conversation conversation, ResultDownloader downloader, FileMetaDataConverter remoteFileItemFactory, Provider<DownloadExceptionHandler> downloadExceptionHandler) { this.conversation = conversation; this.downloader = downloader; this.remoteFileItemFactory = remoteFileItemFactory; this.downloadExceptionHandler = downloadExceptionHandler; } @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e instanceof FormSubmitEvent) { FormSubmitEvent event = (FormSubmitEvent) e; //Just pushed the download the file button... LOG.debugf("File offer download requested. FileId: {0}", event.getData()); try { String dataStr = event.getData(); String fileIdEncoded = dataStr.substring(dataStr.indexOf("=")+1).trim(); String fileId = URLDecoder.decode(fileIdEncoded, "UTF-8"); downloadFileOffer(fileId); } catch(UnsupportedEncodingException uee) { throw new RuntimeException(uee); // impossible } } else if (HyperlinkEvent.EventType.ACTIVATED == e.getEventType()) { handleLinkClick(e.getDescription(), e.getURL()); } } /** * * Download the file offer given a file ID. * <p> * package-private for testing * * @param fileId identifier to look up the file offer message */ void downloadFileOffer(String fileId) { Map<String, MessageFileOffer> fileOffers = conversation.getFileOfferMessages(); MessageFileOffer msgWithfileOffer = fileOffers.get(fileId); SearchResult file = null; try { file = remoteFileItemFactory.create(msgWithfileOffer.getPresence(), msgWithfileOffer.getFileOffer()); DownloadItem dl = downloader.addDownload(null, Collections.singletonList(file)); // Track download states by adding listeners to dl item addPropertyListener(dl, msgWithfileOffer); } catch (DownloadException e) { final SearchResult remoteFileItem = file; final MessageFileOffer messageFileOffer = msgWithfileOffer; downloadExceptionHandler.get().handleDownloadException(new DownloadAction() { @Override public void download(File saveFile, boolean overwrite) throws DownloadException { DownloadItem dl = downloader.addDownload(null, Collections.singletonList(remoteFileItem), saveFile, overwrite); addPropertyListener(dl, messageFileOffer); } @Override public void downloadCanceled(DownloadException ignored) { //nothing to do } }, e, true); } catch (InvalidDataException ide) { // this means the FileMetaData we received isn't well-formed. LOG.error("Unable to access remote file", ide); FocusJOptionPane.showMessageDialog(null, I18n.tr("Unable to access remote file"), I18n.tr("Hyperlink"), JOptionPane.WARNING_MESSAGE); } } private void handleLinkClick(String linkDescription, URL url) { if (ChatDocumentBuilder.LIBRARY_LINK.equals(linkDescription)) { ChatFriend libraryChatFriend = conversation.getChatFriend(); LOG.debugf("Opening a view to {0}'s library", libraryChatFriend.getName()); // libraryNavigator.selectFriendLibrary(libraryChatFriend.getFriend()); throw new IllegalStateException("action does't exist"); } else if (ChatDocumentBuilder.MY_LIBRARY_LINK.equals(linkDescription)) { LOG.debugf("Opening a view to my library"); // libraryNavigator.selectLibrary(); throw new IllegalStateException("action does't exist"); } else { LOG.debugf("Hyperlink clicked: {0}", linkDescription); if (linkDescription.startsWith("magnet")) { //TODO: Need to do something with magnet links } else if (url != null) { NativeLaunchUtils.openURL(url.toString()); } } } private void addPropertyListener(DownloadItem dl, final MessageFileOffer msgWithfileOffer) { dl.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("state".equals(evt.getPropertyName())) { DownloadState state = (DownloadState) evt.getNewValue(); msgWithfileOffer.setDownloadState(state); conversation.displayMessages(); } } }); } }