/*
* ImportContactsTransferHandler.java
*/
package esmska.gui.dnd;
import esmska.Context;
import esmska.data.Contact;
import esmska.gui.ImportFrame;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.TransferHandler;
import org.apache.commons.lang.StringUtils;
/**
* Transfer handler for importing contacts to Esmska.
* Allows to drop vCard (vcard, vcf) files or string with contact name/number.
*
* @author Marian Bouček
* @version 1.0
*/
public class ImportContactsTransferHandler extends TransferHandler {
private static final Logger logger = Logger.getLogger(ImportContactsTransferHandler.class.getName());
private static DataFlavor uriListFlavor; //flavor for dropping files in Gnome or KDE
static {
try {
uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
} catch (ClassNotFoundException ex) {
assert false : "Can't happen";
ex.printStackTrace();
}
}
@Override
public boolean canImport(TransferSupport support) {
if (!support.isDrop()) {
return false;
}
if (!support.isDataFlavorSupported(DataFlavor.javaFileListFlavor) &&
!support.isDataFlavorSupported(uriListFlavor) &&
!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
support.setDropAction(TransferHandler.COPY);
return true;
}
@Override
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
logger.warning("Can't import contacts data by drag&drop, unsupported format.");
return false;
}
try {
//we must try uriListFlavor before stringFlavor, because stringFlavor
//appears to be subset of it
if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor) ||
support.isDataFlavorSupported(uriListFlavor)) {
//dropped a file
if (!isVCard(support)) {
logger.warning("Can't import contacts data by drag&drop, not a vCard file.");
return false;
}
List<File> files = getInputFiles(support);
String fileName = files.get(0).getAbsolutePath();
ImportFrame importFrame = new ImportFrame();
importFrame.setLocationRelativeTo(Context.mainFrame);
importFrame.importVCardFile(fileName);
importFrame.setVisible(true);
} else if (support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
//dropped a string
String data = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor);
//decide if name or number
String name = null, number = null;
StringUtils.trim(data);
if (data == null || data.length() > 100 || data.contains("\n")) {
//no data, too long or not valid
logger.warning("Can't import contacts data by drag&drop, not a valid string.");
return false;
}
String pNumber = Contact.parseNumber(data);
Matcher matcher = Pattern.compile("[+0-9]").matcher(data);
int numbers = 0;
while (matcher.find()) {
numbers++;
}
if (pNumber != null && numbers > data.length() / 2) {
//at least 50% chars were numbers, it's a number
number = pNumber;
} else {
//it's name
name = data;
}
Contact skeleton = new Contact(name, number, null);
Context.mainFrame.getContactPanel().showAddContactDialog(skeleton);
} else {
String msg = "Unknown supported DnD flavor: " + Arrays.toString(support.getDataFlavors());
assert false : msg;
logger.warning(msg);
}
} catch (Exception ex) {
logger.log(Level.INFO, "Problem getting dropped data", ex);
return false;
}
return true;
}
/** Check if transfer support contains exactly one vCard file */
private boolean isVCard(TransferSupport support)
throws UnsupportedFlavorException, IOException {
List<File> files = getInputFiles(support);
if (files.size() != 1) {
return false;
}
String fileName = files.get(0).getAbsolutePath();
String lower = fileName.toLowerCase();
boolean supported = lower.endsWith("vcard") || lower.endsWith("vcf");
return supported;
}
@SuppressWarnings("unchecked")
/** Get list of files from transfer support */
private List<File> getInputFiles(TransferSupport support)
throws UnsupportedFlavorException, IOException {
if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
Object data = support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
return (List<File>) data;
} else if (support.isDataFlavorSupported(uriListFlavor)) {
Object data = support.getTransferable().getTransferData(uriListFlavor);
return textURIListToFileList((String) data);
} else {
return Collections.emptyList();
}
}
/** Convert list of URIs to list of files */
private static List<File> textURIListToFileList(String data) {
List<File> list = new ArrayList<File>(1);
for (StringTokenizer st = new StringTokenizer(data, "\r\n");
st.hasMoreTokens();) {
String s = st.nextToken();
if (s.startsWith("#")) {
// the line is a comment (as per the RFC 2483)
continue;
}
try {
URI uri = new URI(s);
File file = new File(uri);
list.add(file);
} catch (java.net.URISyntaxException e) {
// malformed URI
} catch (IllegalArgumentException e) {
// the URI is not a valid 'file:' URI
}
}
return list;
}
}