kurldrag.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 2000 David Faure <faure@kde.org> 00003 00004 This program is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this program; see the file COPYING. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kurldrag.h" 00021 #include <qstrlist.h> 00022 #include <qdragobject.h> 00023 #include <qfont.h> 00024 #include <unistd.h> 00025 00026 #include <kdeversion.h> 00027 #include <kglobal.h> 00028 #include <klocale.h> 00029 #include <kdebug.h> 00030 00031 class KURLDragPrivate 00032 { 00033 public: 00034 bool m_exportAsText; 00035 }; 00036 00037 KURLDrag::KURLDrag( const KURL::List &urls, QWidget* dragSource, const char * name ) 00038 : QUriDrag(dragSource, name), m_metaData(), d( 0 ) 00039 { 00040 init(urls); 00041 } 00042 00043 KURLDrag::KURLDrag( const KURL::List &urls, const QMap<QString,QString>& metaData, 00044 QWidget* dragSource, const char * name ) 00045 : QUriDrag(dragSource, name), m_metaData(metaData), d( 0 ) 00046 { 00047 init(urls); 00048 } 00049 00050 KURLDrag::~KURLDrag() 00051 { 00052 delete d; 00053 } 00054 00055 void KURLDrag::init(const KURL::List &urls) 00056 { 00057 KURL::List::ConstIterator uit = urls.begin(); 00058 KURL::List::ConstIterator uEnd = urls.end(); 00059 // Get each URL encoded in utf8 - and since we get it in escaped 00060 // form on top of that, .latin1() is fine. 00061 for ( ; uit != uEnd ; ++uit ) 00062 { 00063 m_urls.append( urlToString(*uit).latin1() ); 00064 } 00065 setUris(m_urls); 00066 } 00067 00068 void KURLDrag::setExportAsText( bool exp ) 00069 { 00070 // For now d is only used here, so create it on demand 00071 if ( !d ) 00072 d = new KURLDragPrivate; 00073 d->m_exportAsText = exp; 00074 } 00075 00076 KURLDrag * KURLDrag::newDrag( const KURL::List &urls, QWidget* dragSource, const char * name ) 00077 { 00078 return new KURLDrag( urls, QMap<QString, QString>(), dragSource, name ); 00079 } 00080 00081 KURLDrag * KURLDrag::newDrag( const KURL::List &urls, const QMap<QString, QString>& metaData, 00082 QWidget* dragSource, const char * name ) 00083 { 00084 return new KURLDrag( urls, metaData, dragSource, name ); 00085 } 00086 00087 bool KURLDrag::decode( const QMimeSource *e, KURL::List &uris ) 00088 { 00089 if ( e->provides( "application/x-kde-urilist" ) ) { 00090 QByteArray payload = e->encodedData( "application/x-kde-urilist" ); 00091 if ( payload.size() ) { 00092 uint c=0; 00093 const char* d = payload.data(); 00094 while (c < payload.size() && d[c]) { 00095 uint f = c; 00096 // Find line end 00097 while (c < payload.size() && d[c] && d[c]!='\r' 00098 && d[c] != '\n') 00099 c++; 00100 QCString s(d+f,c-f+1); 00101 if ( s[0] != '#' ) // non-comment? 00102 uris.append(stringToUrl(s)); 00103 // Skip junk 00104 while (c < payload.size() && d[c] && 00105 (d[c]=='\n' || d[c]=='\r')) 00106 c++; 00107 } 00108 return !uris.isEmpty(); 00109 } 00110 } 00111 00112 QStrList lst; 00113 QUriDrag::decode( e, lst ); 00114 for (QStrListIterator it(lst); *it; ++it) 00115 { 00116 KURL url = stringToUrl( *it ); 00117 if ( !url.isValid() ) 00118 { 00119 uris.clear(); 00120 break; 00121 } 00122 uris.append( url ); 00123 } 00124 return !uris.isEmpty(); 00125 } 00126 00127 bool KURLDrag::decode( const QMimeSource *e, KURL::List &uris, QMap<QString,QString>& metaData ) 00128 { 00129 if ( decode( e, uris ) ) // first decode the URLs (see above) 00130 { 00131 QByteArray ba = e->encodedData( "application/x-kio-metadata" ); 00132 if ( ba.size() ) 00133 { 00134 QString s = ba.data(); 00135 QStringList l = QStringList::split( "$@@$", s ); 00136 QStringList::ConstIterator it = l.begin(); 00137 bool readingKey = true; // true, then false, then true, etc. 00138 QString key; 00139 for ( ; it != l.end(); ++it ) { 00140 if ( readingKey ) 00141 key = *it; 00142 else 00143 metaData.replace( key, *it ); 00144 readingKey = !readingKey; 00145 } 00146 Q_ASSERT( readingKey ); // an odd number of items would be, well, odd ;-) 00147 } 00148 return true; // Success, even if no metadata was found 00149 } 00150 return false; // Couldn't decode the URLs 00151 } 00152 00153 #ifdef Q_WS_QWS 00154 bool KURLDrag::decode( QStringList const &e, KURL::List &uris ) 00155 { 00156 QStringList::ConstIterator end(e.end()); 00157 for(QStringList::ConstIterator it=e.begin(); it!=end; ++it) 00158 { 00159 KURL url = KURL( *it, 106 ); // 106 is mib enum for utf8 codec 00160 if ( !url.isValid() ) 00161 { 00162 uris.clear(); 00163 break; 00164 } 00165 uris.append( url ); 00166 } 00167 return !uris.isEmpty(); 00168 } 00169 #endif 00170 00172 00173 const char * KURLDrag::format( int i ) const 00174 { 00175 if ( i == 0 ) 00176 return "text/uri-list"; 00177 else if ( i == 1 ) 00178 return "application/x-kio-metadata"; 00179 if ( d && d->m_exportAsText == false ) 00180 return 0; 00181 if ( i == 2 ) 00182 return "text/plain"; 00183 else if ( i == 3 ) //Support this for apps that use plain XA_STRING clipboard 00184 return "text/plain;charset=ISO-8859-1"; 00185 else if ( i == 4 ) //Support this for apps that use the UTF_STRING clipboard 00186 return "text/plain;charset=UTF-8"; 00187 else return 0; 00188 } 00189 00190 QByteArray KURLDrag::encodedData( const char* mime ) const 00191 { 00192 QByteArray a; 00193 QCString mimetype( mime ); 00194 if ( mimetype == "text/uri-list" ) 00195 return QUriDrag::encodedData( mime ); 00196 else if ( mimetype == "text/plain" ) 00197 { 00198 QStringList uris; 00199 for (QStrListIterator it(m_urls); *it; ++it) 00200 uris.append(stringToUrl(*it).prettyURL()); 00201 00202 QCString s = uris.join( "\n" ).local8Bit(); 00203 if( uris.count() > 1 ) // terminate last line, unless it's the only line 00204 s.append( "\n" ); 00205 a.resize( s.length()); 00206 memcpy( a.data(), s.data(), s.length()); // no trailing zero in clipboard text 00207 } 00208 else if ( mimetype.lower() == "text/plain;charset=iso-8859-1") 00209 { 00210 QStringList uris; 00211 for (QStrListIterator it(m_urls); *it; ++it) 00212 for (QStrListIterator it(m_urls); *it; ++it) 00213 uris.append(stringToUrl(*it).url(0, 4)); // 4 is mib for latin1 00214 00215 QCString s = uris.join( "\n" ).latin1(); 00216 if( uris.count() > 1 ) 00217 s.append( "\n" ); 00218 a.resize( s.length()); 00219 memcpy( a.data(), s.data(), s.length()); 00220 } 00221 else if ( mimetype.lower() == "text/plain;charset=utf-8") 00222 { 00223 QStringList uris; 00224 for (QStrListIterator it(m_urls); *it; ++it) 00225 uris.append(stringToUrl(*it).prettyURL()); 00226 00227 QCString s = uris.join( "\n" ).utf8(); 00228 if( uris.count() > 1 ) 00229 s.append( "\n" ); 00230 a.resize( s.length()); 00231 memcpy( a.data(), s.data(), s.length()); 00232 } 00233 else if ( mimetype == "application/x-kio-metadata" ) 00234 { 00235 if ( !m_metaData.isEmpty() ) 00236 { 00237 QString s; 00238 QMap<QString,QString>::ConstIterator it; 00239 for( it = m_metaData.begin(); it != m_metaData.end(); ++it ) 00240 { 00241 s += it.key(); 00242 s += "$@@$"; 00243 s += it.data(); 00244 s += "$@@$"; 00245 } 00246 a.resize( s.length() + 1 ); 00247 memcpy( a.data(), s.latin1(), a.size() ); 00248 } 00249 } 00250 return a; 00251 } 00252 00253 KURL KURLDrag::stringToUrl(const QCString &s) 00254 { 00255 if (strncmp(s.data(), "file:", 5) == 0) 00256 return KURL(s, KGlobal::locale()->fileEncodingMib()); 00257 00258 return KURL(s, 106); // 106 is mib enum for utf8 codec; 00259 } 00260 00261 QString KURLDrag::urlToString(const KURL &url) 00262 { 00263 if (url.isLocalFile()) 00264 { 00265 #if 1 00266 return url.url(0, KGlobal::locale()->fileEncodingMib()); 00267 #else 00268 // According to the XDND spec, file:/ URLs for DND must have 00269 // the hostname part. But in really it just breaks many apps, 00270 // so it's disabled for now. 00271 QString s = url.url(0, KGlobal::locale()->fileEncodingMib()); 00272 if( !s.startsWith( "file://" )) 00273 { 00274 char hostname[257]; 00275 if ( gethostname( hostname, 255 ) == 0 ) 00276 { 00277 hostname[256] = '\0'; 00278 return QString( "file://" ) + hostname + s.mid( 5 ); 00279 } 00280 } 00281 #endif 00282 } 00283 00284 if ( url.protocol() == "mailto" ) { 00285 return url.path(); 00286 } 00287 00288 return url.url(0, 106); // 106 is mib enum for utf8 codec 00289 } 00290 00291 // deprecated ctor 00292 KURLDrag::KURLDrag( const QStrList & urls, const QMap<QString,QString>& metaData, 00293 QWidget * dragSource, const char* name ) : 00294 QUriDrag( urls, dragSource, name ), m_urls( urls ), m_metaData( metaData ), d( 0 ) {}