1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 #include <sal/types.h>
31 
32 #ifndef _TRANSFERABLE_HXX_
33 #include "OSXTransferable.hxx"
34 #endif
35 
36 #include "DataFlavorMapping.hxx"
37 
38 using namespace rtl;
39 using namespace std;
40 using namespace osl;
41 using namespace cppu;
42 using namespace com::sun::star::uno;
43 using namespace com::sun::star::datatransfer;
44 using namespace com::sun::star::io;
45 using namespace com::sun::star::lang;
46 using namespace com::sun::star::container;
47 
48 const Type CPPUTYPE_SEQINT8  = getCppuType((Sequence<sal_Int8>*)0);
49 const Type CPPUTYPE_OUSTRING = getCppuType((OUString*)0);
50 
51 namespace // private
52 {
53 	bool isValidFlavor( const DataFlavor& aFlavor )
54 	{
55 	  size_t len = aFlavor.MimeType.getLength();
56 	  Type dtype = aFlavor.DataType;
57 	  return ((len > 0) && ((dtype == CPPUTYPE_SEQINT8) || (dtype == CPPUTYPE_OUSTRING)));
58 	}
59 
60 } // namespace private
61 
62 
63 OSXTransferable::OSXTransferable(const Reference<XMimeContentTypeFactory> rXMimeCntFactory,
64 								 DataFlavorMapperPtr_t pDataFlavorMapper,
65 								 NSPasteboard* pasteboard) :
66   mrXMimeCntFactory(rXMimeCntFactory),
67   mDataFlavorMapper(pDataFlavorMapper),
68   mPasteboard(pasteboard)
69 {
70   [mPasteboard retain];
71 
72   initClipboardItemList();
73 }
74 
75 
76 OSXTransferable::~OSXTransferable()
77 {
78   [mPasteboard release];
79 }
80 
81 
82 Any SAL_CALL OSXTransferable::getTransferData( const DataFlavor& aFlavor )
83   throw( UnsupportedFlavorException, IOException, RuntimeException )
84 {
85   if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor))
86 	{
87 	  throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
88 									   static_cast<XTransferable*>(this));
89 	}
90 
91   NSString* sysFormat =
92       (aFlavor.MimeType.compareToAscii( "image/bmp", 9 ) == 0)
93       ? mDataFlavorMapper->openOfficeImageToSystemFlavor( mPasteboard )
94       : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor);
95   DataProviderPtr_t dp;
96 
97   if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame)
98 	{
99 	  NSArray* sysData = [mPasteboard propertyListForType: sysFormat];
100 	  dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
101 	}
102   else
103 	{
104 	  NSData* sysData = [mPasteboard dataForType: sysFormat];
105 	  dp = mDataFlavorMapper->getDataProvider(sysFormat, sysData);
106 	}
107 
108   if (dp.get() == NULL)
109 	{
110 	  throw UnsupportedFlavorException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Unsupported data flavor")),
111 									   static_cast<XTransferable*>(this));
112 	}
113 
114   return dp->getOOoData();
115 }
116 
117 
118 bool OSXTransferable::isUnicodeText(const DataFlavor& flavor)
119 {
120   return (flavor.DataType == CPPUTYPE_OUSTRING);
121 }
122 
123 
124 Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors(  )
125 	throw( RuntimeException )
126 {
127   return mFlavorList;
128 }
129 
130 
131 sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor)
132 	throw( RuntimeException )
133 {
134 	for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++)
135 	  if (compareDataFlavors(aFlavor, mFlavorList[i]))
136 		return sal_True;
137 
138 	return sal_False;
139 }
140 
141 
142 void OSXTransferable::initClipboardItemList()
143 {
144   NSArray* pboardFormats = [mPasteboard types];
145 
146   if (pboardFormats == NULL)
147 	{
148 	  throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("AquaClipboard: Cannot get clipboard data")),
149 							 static_cast<XTransferable*>(this));
150 	}
151 
152   mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats);
153 }
154 
155 
156 /* Compares two DataFlavors. Returns true if both DataFlavor have the same media type
157    and the number of parameter and all parameter values do match otherwise false
158    is returned.
159  */
160 bool OSXTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs )
161 {
162 	try
163 	{
164 		Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType));
165 		Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType));
166 
167 		if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) ||
168 			!cmpAllContentTypeParameter(xLhs, xRhs))
169 		  {
170 			return false;
171 		  }
172 	}
173 	catch( IllegalArgumentException& )
174 	{
175 		OSL_ENSURE( sal_False, "Invalid content type detected" );
176 		return false;
177 	}
178 
179 	return true;
180 }
181 
182 
183 bool OSXTransferable::cmpAllContentTypeParameter(const Reference<XMimeContentType> xLhs,
184 											   const Reference<XMimeContentType> xRhs) const
185 {
186   Sequence<OUString> xLhsFlavors = xLhs->getParameters();
187   Sequence<OUString> xRhsFlavors = xRhs->getParameters();
188 
189   // Stop here if the number of parameters is different already
190   if (xLhsFlavors.getLength() != xRhsFlavors.getLength())
191 	return false;
192 
193   try
194 	{
195 	  OUString pLhs;
196 	  OUString pRhs;
197 
198 	  for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++)
199 		{
200 		  pLhs = xLhs->getParameterValue(xLhsFlavors[i]);
201 		  pRhs = xRhs->getParameterValue(xLhsFlavors[i]);
202 
203 		  if (!pLhs.equalsIgnoreAsciiCase(pRhs))
204 			{
205 			  return false;
206 			}
207 		}
208 	}
209   catch(IllegalArgumentException&)
210 	{
211 	  return false;
212 	}
213 
214   return true;
215 }
216