• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

paste.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include "paste.h"
00020 #include "pastedialog.h"
00021 
00022 #include "kio/copyjob.h"
00023 #include "kio/deletejob.h"
00024 #include "kio/global.h"
00025 #include "kio/netaccess.h"
00026 #include "kio/renamedialog.h"
00027 #include "kio/kprotocolmanager.h"
00028 #include "jobuidelegate.h"
00029 
00030 #include <kurl.h>
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 #include <kinputdialog.h>
00034 #include <kmessagebox.h>
00035 #include <kmimetype.h>
00036 #include <ktemporaryfile.h>
00037 
00038 #include <QtGui/QApplication>
00039 #include <QtGui/QClipboard>
00040 #include <QMimeData>
00041 #include <QtCore/QTextIStream>
00042 
00043 static KUrl getNewFileName( const KUrl &u, const QString& text, QWidget *widget )
00044 {
00045   bool ok;
00046   QString dialogText( text );
00047   if ( dialogText.isEmpty() )
00048     dialogText = i18n( "Filename for clipboard content:" );
00049   QString file = KInputDialog::getText( QString(), dialogText, QString(), &ok, widget );
00050   if ( !ok )
00051      return KUrl();
00052 
00053   KUrl myurl(u);
00054   myurl.addPath( file );
00055 
00056   // Check for existing destination file. If we let CopyJob do it then we expose
00057   // an ugly tempfile name as the source URL...
00058   if (KIO::NetAccess::exists(myurl, KIO::NetAccess::DestinationSide, widget))
00059   {
00060       kDebug(7007) << "Paste will overwrite file.  Prompting...";
00061       KIO::RenameDialog_Result res = KIO::R_OVERWRITE;
00062 
00063       KIO::RenameDialog dlg( widget,
00064                           i18n("File Already Exists"),
00065                           u.pathOrUrl(),
00066                           myurl.pathOrUrl(),
00067                           (KIO::RenameDialog_Mode) (KIO::M_OVERWRITE | KIO::M_SINGLE) );
00068       res = static_cast<KIO::RenameDialog_Result>(dlg.exec());
00069 
00070       if ( res == KIO::R_RENAME )
00071       {
00072           myurl = dlg.newDestUrl();
00073       }
00074       else if ( res == KIO::R_CANCEL )
00075       {
00076           return KUrl();
00077       } else if (res == KIO::R_OVERWRITE)
00078       {
00079           // Ideally we would just pass KIO::Overwrite to the job in pasteDataAsyncTo.
00080           // But 1) CopyJob doesn't support that (it wouldn't really apply to multiple files)
00081           // 2) we can't use file_move because CopyJob* is everywhere in the API (see TODO)
00082           // As solution 1bis) we could use a PredefinedAnswerJobUiDelegate like in kiotesthelper.h...
00083           // But well the simpler is really to delete the dest:
00084           KIO::Job* delJob = KIO::del(myurl);
00085           delJob->exec();
00086       }
00087   }
00088 
00089   return myurl;
00090 }
00091 
00092 // The final step: write _data to tempfile and move it to newUrl
00093 static KIO::CopyJob* pasteDataAsyncTo( const KUrl& newUrl, const QByteArray& _data )
00094 {
00095     // ### Bug: because we move from a tempfile to the destination,
00096     // if the user does "Undo" then we won't ask for confirmation, and we'll
00097     // move back to a tempfile, instead of just deleting.
00098     // I guess we need a macro job which does copy+del?
00099     // A KIO::storedPut would be better but FileUndoManager would need to support it first.
00100     KTemporaryFile tempFile;
00101     tempFile.setAutoRemove(false);
00102     tempFile.open();
00103     tempFile.write(_data.data(), _data.size());
00104     tempFile.flush();
00105 
00106     KUrl origUrl(tempFile.fileName());
00107 
00108     return KIO::move(origUrl, newUrl);
00109 }
00110 
00111 #ifndef QT_NO_MIMECLIPBOARD
00112 static KIO::CopyJob* chooseAndPaste( const KUrl& u, const QMimeData* mimeData,
00113                                      const QStringList& formats,
00114                                      const QString& text,
00115                                      QWidget* widget,
00116                                      bool clipboard )
00117 {
00118     QStringList formatLabels;
00119     for ( int i = 0; i < formats.size(); ++i ) {
00120         const QString& fmt = formats[i];
00121         KMimeType::Ptr mime = KMimeType::mimeType(fmt, KMimeType::ResolveAliases);
00122         if (mime)
00123             formatLabels.append( i18n("%1 (%2)", mime->comment(), fmt) );
00124         else
00125             formatLabels.append( fmt );
00126     }
00127 
00128     QString dialogText( text );
00129     if ( dialogText.isEmpty() )
00130         dialogText = i18n( "Filename for clipboard content:" );
00131     //using QString() instead of QString::null didn't compile (with gcc 3.2.3), because the ctor was mistaken as a function declaration, Alex //krazy:exclude=nullstrassign
00132     KIO::PasteDialog dlg( QString::null, dialogText, QString(), formatLabels, widget, clipboard ); //krazy:exclude=nullstrassign
00133 
00134     if ( dlg.exec() != KDialog::Accepted )
00135         return 0;
00136 
00137     if ( clipboard && dlg.clipboardChanged() ) {
00138         KMessageBox::sorry( widget,
00139                             i18n( "The clipboard has changed since you used 'paste': "
00140                                   "the chosen data format is no longer applicable. "
00141                                   "Please copy again what you wanted to paste." ) );
00142         return 0;
00143     }
00144 
00145     const QString result = dlg.lineEditText();
00146     const QString chosenFormat = formats[ dlg.comboItem() ];
00147 
00148     kDebug() << " result=" << result << " chosenFormat=" << chosenFormat;
00149     KUrl newUrl( u );
00150     newUrl.addPath( result );
00151     // if "data" came from QClipboard, then it was deleted already - by a nice 0-seconds timer
00152     // In that case, get it again. Let's hope the user didn't copy something else meanwhile :/
00153     // #### QT4/KDE4 TODO: check that this is still the case
00154     if ( clipboard ) {
00155         mimeData = QApplication::clipboard()->mimeData();
00156     }
00157     const QByteArray ba = mimeData->data( chosenFormat );
00158     KIO::CopyJob* job = pasteDataAsyncTo( newUrl, ba );
00159     job->ui()->setWindow(widget);
00160     return job;
00161 }
00162 #endif
00163 
00164 
00165 #ifndef QT_NO_MIMECLIPBOARD
00166 
00167 static QStringList extractFormats(const QMimeData* mimeData)
00168 {
00169     QStringList formats;
00170     const QStringList allFormats = mimeData->formats();
00171     for (QStringList::const_iterator it = allFormats.constBegin(), end = allFormats.constEnd();
00172          it != end; ++it) {
00173         if ((*it) == QLatin1String("application/x-qiconlist")) // see QIconDrag
00174             continue;
00175         if ((*it) == QLatin1String("application/x-kde-cutselection")) // see KonqDrag
00176             continue;
00177         if (!(*it).contains(QLatin1Char('/'))) // e.g. TARGETS, MULTIPLE, TIMESTAMP
00178             continue;
00179         formats.append(*it);
00180     }
00181     return formats;
00182 }
00183 
00184 // The main method for dropping
00185 KIO::CopyJob* KIO::pasteMimeSource( const QMimeData* mimeData, const KUrl& destUrl,
00186                                     const QString& dialogText, QWidget* widget, bool clipboard )
00187 {
00188   QByteArray ba;
00189 
00190   // Now check for plain text
00191   // We don't want to display a mimetype choice for a QTextDrag, those mimetypes look ugly.
00192   QString text;
00193   if ( mimeData->hasText() )
00194   {
00195       ba = mimeData->text().toLocal8Bit(); // encoding OK?
00196   }
00197   else
00198   {
00199       const QStringList formats = extractFormats(mimeData);
00200       if ( formats.size() == 0 )
00201           return 0;
00202 
00203       if ( formats.size() > 1 ) {
00204           return chooseAndPaste( destUrl, mimeData, formats, dialogText, widget, clipboard );
00205       }
00206       ba = mimeData->data( formats.first() );
00207   }
00208   if ( ba.isEmpty() )
00209   {
00210     KMessageBox::sorry( widget, i18n("The clipboard is empty") );
00211     return 0;
00212   }
00213 
00214   return pasteDataAsync( destUrl, ba, widget, dialogText );
00215 }
00216 
00217 KIO_EXPORT bool KIO::canPasteMimeSource(const QMimeData* data)
00218 {
00219     return data->hasText() || !extractFormats(data).isEmpty();
00220 }
00221 
00222 #endif
00223 
00224 // The main method for pasting
00225 KIO_EXPORT KIO::Job *KIO::pasteClipboard( const KUrl& destUrl, QWidget* widget, bool move )
00226 {
00227   if ( !destUrl.isValid() ) {
00228     KMessageBox::error( widget, i18n( "Malformed URL\n%1", destUrl.prettyUrl() ) );
00229     return 0;
00230   }
00231 
00232 #ifndef QT_NO_MIMECLIPBOARD
00233   const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00234 
00235   // First check for URLs.
00236   const KUrl::List urls = KUrl::List::fromMimeData(mimeData, KUrl::List::PreferLocalUrls);
00237   if ( !urls.isEmpty() ) {
00238     KIO::Job *res = 0;   
00239     if ( move )
00240       res = KIO::move( urls, destUrl );
00241     else
00242       res = KIO::copy( urls, destUrl );
00243     res->ui()->setWindow(widget);
00244 
00245     // If moving, update the clipboard contents with the new locations
00246     if ( move ) {
00247       QApplication::clipboard()->clear();
00248 
00249       KUrl::List newUrls;
00250       for (int i = 0; i < urls.size(); i++) {
00251           KUrl dUrl = destUrl;
00252           dUrl.addPath(urls.at(i).fileName());
00253           newUrls.append(dUrl);
00254       }
00255 
00256       QMimeData* mime = new QMimeData();
00257       newUrls.populateMimeData(mime);
00258       QApplication::clipboard()->setMimeData(mime);
00259     }  
00260       
00261     return res;
00262   }
00263   return pasteMimeSource( mimeData, destUrl, QString(), widget, true /*clipboard*/ );
00264 #else
00265   QByteArray ba;
00266   QTextStream txtStream( ba, QIODevice::WriteOnly );
00267 
00268   QStringList data = QApplication::clipboard()->text().split('\n', QString::SkipEmptyParts);
00269 
00270   KUrl::List urls;
00271   KURLDrag::decode(data, urls);
00272   QStringList::const_iterator end(data.end());
00273   for(QStringList::const_iterator it=data.begin(); it!=end; ++it)
00274       txtStream << *it;
00275   if ( ba.size() == 0 )
00276   {
00277     KMessageBox::sorry(widget, i18n("The clipboard is empty"));
00278     return 0;
00279   }
00280   return pasteDataAsync( destUrl, ba, widget );
00281 #endif
00282 }
00283 
00284 
00285 KIO_EXPORT void KIO::pasteData( const KUrl& u, const QByteArray& _data, QWidget* widget )
00286 {
00287     const KUrl newUrl = getNewFileName( u, QString(), widget );
00288     // We could use KIO::put here, but that would require a class
00289     // for the slotData call. With NetAccess, we can do a synchronous call.
00290 
00291     if (newUrl.isEmpty())
00292        return;
00293 
00294     KTemporaryFile tempFile;
00295     tempFile.open();
00296     tempFile.write( _data.data(), _data.size() );
00297     tempFile.flush();
00298 
00299     (void) KIO::NetAccess::upload( tempFile.fileName(), newUrl, widget );
00300 }
00301 
00302 // KDE5 TODO: return a KIO::Job*, not a CopyJob*, in case we want to use file_move or a macro job...
00303 // But then the caller needs to know the destUrl too. Return a QPair?
00304 KIO_EXPORT KIO::CopyJob* KIO::pasteDataAsync( const KUrl& u, const QByteArray& _data, QWidget *widget, const QString& text )
00305 {
00306     KUrl newUrl = getNewFileName( u, text, widget );
00307 
00308     if (newUrl.isEmpty())
00309        return 0;
00310 
00311     KIO::CopyJob* job = pasteDataAsyncTo( newUrl, _data );
00312     job->ui()->setWindow(widget);
00313     return job;
00314 }
00315 
00316 // NOTE: DolphinView::pasteInfo() has a better version of this
00317 // (but which requires KonqFileItemCapabilities)
00318 KIO_EXPORT QString KIO::pasteActionText()
00319 {
00320     const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00321     KUrl::List urls = KUrl::List::fromMimeData( mimeData );
00322     if ( !urls.isEmpty() ) {
00323         if ( urls.first().isLocalFile() )
00324             return i18np( "&Paste File", "&Paste %1 Files", urls.count() );
00325         else
00326             return i18np( "&Paste URL", "&Paste %1 URLs", urls.count() );
00327     } else if ( !mimeData->formats().isEmpty() ) {
00328         return i18n( "&Paste Clipboard Contents" );
00329     } else {
00330         return QString();
00331     }
00332 }

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal