/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.gui.main.chat;
import java.awt.datatransfer.*;
import java.awt.im.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.contactlist.*;
import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
/**
* A TransferHandler that we use to handle copying, pasting and DnD operations
* in our <tt>ChatPanel</tt>. The string handler is heavily inspired
* by Sun's <tt>DefaultTransferHandler</tt> with the main difference being that
* we only accept pasting of plain text. We do this in order to avoid HTML
* support problems that appear when pasting formatted text into our editable
* area.
*
* @author Emil Ivov
* @author Yana Stamcheva
*/
public class ChatTransferHandler
extends ExtendedTransferHandler
{
/**
* The data flavor used when transferring <tt>UIContact</tt>s.
*/
protected static final DataFlavor uiContactDataFlavor
= new DataFlavor(UIContact.class, "UIContact");
/**
* This class logger.
*/
private final static Logger logger
= Logger.getLogger(ChatTransferHandler.class);
/**
* The data flavor used when transferring <tt>File</tt>s under Linux.
*/
private static DataFlavor uriListFlavor;
static
{
try
{
uriListFlavor =
new DataFlavor("text/uri-list;class=java.lang.String");
} catch (ClassNotFoundException e)
{
// can't happen
logger.error("", e);
}
}
/**
* The chat panel involved in the copy/paste/DnD operation.
*/
private final ChatPanel chatPanel;
/**
* Constructs the <tt>ChatTransferHandler</tt> by specifying the
* <tt>ChatPanel</tt> we're currently dealing with.
*
* @param chatPanel the <tt>ChatPanel</tt> we're currently dealing with
*/
public ChatTransferHandler(ChatPanel chatPanel)
{
this.chatPanel = chatPanel;
}
/**
* Indicates whether a component will accept an import of the given
* set of data flavors prior to actually attempting to import it. We return
* <tt>true</tt> to indicate that the transfer with at least one of the
* given flavors would work and <tt>false</tt> to reject the transfer.
* <p>
* @param comp component
* @param flavor the data formats available
* @return true if the data can be inserted into the component, false
* otherwise
* @throws NullPointerException if <code>support</code> is {@code null}
*/
@Override
public boolean canImport(JComponent comp, DataFlavor flavor[])
{
for(DataFlavor f: flavor)
{
if (f.equals(uiContactDataFlavor) || f.equals(uriListFlavor))
return true;
}
return super.canImport(comp, flavor);
}
/**
* Handles transfers to the chat panel from the clip board or a
* DND drop operation. The <tt>Transferable</tt> parameter contains the
* data that needs to be imported.
* <p>
* @param comp the component to receive the transfer;
* @param t the data to import
* @return true if the data was inserted into the component and false
* otherwise
*/
@Override
@SuppressWarnings("unchecked") //the case is taken care of
public boolean importData(JComponent comp, Transferable t)
{
if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
{
try
{
Object o = t.getTransferData(DataFlavor.javaFileListFlavor);
if (o instanceof java.util.Collection)
{
Collection<File> files = (Collection<File>) o;
for(File file: files)
chatPanel.sendFile(file);
// Otherwise fire files dropped event.
return true;
}
}
catch (UnsupportedFlavorException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop files.", e);
}
catch (IOException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop files.", e);
}
}
if (t.isDataFlavorSupported(uriListFlavor))
{
try
{
Object o = t.getTransferData(uriListFlavor);
boolean dataProcessed = false;
StringTokenizer tokens = new StringTokenizer((String)o);
while (tokens.hasMoreTokens())
{
String urlString = tokens.nextToken();
URL url = new URL(urlString);
File file = new File(
URLDecoder.decode(url.getFile(), "UTF-8"));
chatPanel.sendFile(file);
dataProcessed = true;
}
return dataProcessed;
}
catch (UnsupportedFlavorException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop files.", e);
}
catch (IOException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop files.", e);
}
}
if (t.isDataFlavorSupported(uiContactDataFlavor))
{
Object o = null;
try
{
o = t.getTransferData(uiContactDataFlavor);
}
catch (UnsupportedFlavorException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop meta contact.", e);
}
catch (IOException e)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop meta contact.", e);
}
if (o instanceof ContactNode)
{
UIContact uiContact
= ((ContactNode) o).getContactDescriptor();
// We only support drag&drop for MetaContacts for now.
if (!(uiContact instanceof MetaUIContact))
return false;
ChatTransport currentChatTransport
= chatPanel.getChatSession().getCurrentChatTransport();
Iterator<Contact> contacts = ((MetaContact) uiContact
.getDescriptor()).getContactsForProvider(
currentChatTransport.getProtocolProvider());
String contact = null;
if (contacts.hasNext())
contact = contacts.next().getAddress();
if (contact != null)
{
List<String> inviteList = new ArrayList<String>();
inviteList.add(contact);
chatPanel.inviteContacts( currentChatTransport,
inviteList, null);
return true;
}
else
new ErrorDialog(
null,
GuiActivator.getResources().getI18NString(
"service.gui.ERROR"),
GuiActivator.getResources().getI18NString(
"service.gui.CONTACT_NOT_SUPPORTING_CHAT_CONF",
new String[]{uiContact.getDisplayName()}))
.showDialog();
}
}
if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
{
InputContext inputContext = comp.getInputContext();
if (inputContext != null)
{
inputContext.endComposition();
}
try
{
BufferedReader reader = new BufferedReader(
DataFlavor.stringFlavor.getReaderForText(t));
StringBuilder buffToPaste = new StringBuilder();
String line = reader.readLine();
while(line != null)
{
buffToPaste.append(line);
//read next line
line = reader.readLine();
if(line != null)
buffToPaste.append("\n");
}
((JTextComponent)comp)
.replaceSelection(buffToPaste.toString());
return true;
}
catch (UnsupportedFlavorException ufe)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop string.", ufe);
}
catch (IOException ioe)
{
if (logger.isDebugEnabled())
logger.debug("Failed to drop string.", ioe);
}
}
return false;
}
}