• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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, const QString& suggestedFileName, 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, suggestedFileName, &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                                      const QString& suggestedFileName,
00116                                      QWidget* widget,
00117                                      bool clipboard )
00118 {
00119     QStringList formatLabels;
00120     for ( int i = 0; i < formats.size(); ++i ) {
00121         const QString& fmt = formats[i];
00122         KMimeType::Ptr mime = KMimeType::mimeType(fmt, KMimeType::ResolveAliases);
00123         if (mime)
00124             formatLabels.append( i18n("%1 (%2)", mime->comment(), fmt) );
00125         else
00126             formatLabels.append( fmt );
00127     }
00128 
00129     QString dialogText( text );
00130     if ( dialogText.isEmpty() )
00131         dialogText = i18n( "Filename for clipboard content:" );
00132     //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
00133     KIO::PasteDialog dlg( QString::null, dialogText, suggestedFileName, formatLabels, widget, clipboard ); //krazy:exclude=nullstrassign
00134 
00135     if ( dlg.exec() != KDialog::Accepted )
00136         return 0;
00137 
00138     if ( clipboard && dlg.clipboardChanged() ) {
00139         KMessageBox::sorry( widget,
00140                             i18n( "The clipboard has changed since you used 'paste': "
00141                                   "the chosen data format is no longer applicable. "
00142                                   "Please copy again what you wanted to paste." ) );
00143         return 0;
00144     }
00145 
00146     const QString result = dlg.lineEditText();
00147     const QString chosenFormat = formats[ dlg.comboItem() ];
00148 
00149     kDebug() << " result=" << result << " chosenFormat=" << chosenFormat;
00150     KUrl newUrl( u );
00151     newUrl.addPath( result );
00152     // if "data" came from QClipboard, then it was deleted already - by a nice 0-seconds timer
00153     // In that case, get it again. Let's hope the user didn't copy something else meanwhile :/
00154     // #### QT4/KDE4 TODO: check that this is still the case
00155     if ( clipboard ) {
00156         mimeData = QApplication::clipboard()->mimeData();
00157     }
00158     const QByteArray ba = mimeData->data( chosenFormat );
00159     KIO::CopyJob* job = pasteDataAsyncTo( newUrl, ba );
00160     job->ui()->setWindow(widget);
00161     return job;
00162 }
00163 #endif
00164 
00165 
00166 #ifndef QT_NO_MIMECLIPBOARD
00167 
00168 static QStringList extractFormats(const QMimeData* mimeData)
00169 {
00170     QStringList formats;
00171     const QStringList allFormats = mimeData->formats();
00172     Q_FOREACH(const QString& format, allFormats) {
00173         if (format == QLatin1String("application/x-qiconlist")) // see QIconDrag
00174             continue;
00175         if (format == QLatin1String("application/x-kde-cutselection")) // see KonqDrag
00176             continue;
00177         if (format == QLatin1String("application/x-kde-suggestedfilename"))
00178             continue;
00179         if (format.startsWith(QLatin1String("application/x-qt-"))) // Qt-internal
00180             continue;
00181         if (format.startsWith(QLatin1String("x-kmail-drag/"))) // app-internal
00182             continue;
00183         if (!format.contains(QLatin1Char('/'))) // e.g. TARGETS, MULTIPLE, TIMESTAMP
00184             continue;
00185         formats.append(format);
00186     }
00187     return formats;
00188 }
00189 
00190 // The main method for dropping
00191 KIO::CopyJob* KIO::pasteMimeSource( const QMimeData* mimeData, const KUrl& destUrl,
00192                                     const QString& dialogText, QWidget* widget, bool clipboard )
00193 {
00194   QByteArray ba;
00195 
00196   const QString suggestedFilename = QString::fromUtf8(mimeData->data("application/x-kde-suggestedfilename"));
00197 
00198   // Now check for plain text
00199   // We don't want to display a mimetype choice for a QTextDrag, those mimetypes look ugly.
00200   QString text;
00201   if ( mimeData->hasText() )
00202   {
00203       ba = mimeData->text().toLocal8Bit(); // encoding OK?
00204   }
00205   else
00206   {
00207       const QStringList formats = extractFormats(mimeData);
00208       if ( formats.size() == 0 )
00209           return 0;
00210 
00211       if ( formats.size() > 1 ) {
00212           return chooseAndPaste(destUrl, mimeData, formats, dialogText, suggestedFilename, widget, clipboard);
00213       }
00214       ba = mimeData->data( formats.first() );
00215   }
00216   if ( ba.isEmpty() )
00217   {
00218     KMessageBox::sorry( widget, i18n("The clipboard is empty") );
00219     return 0;
00220   }
00221 
00222     const KUrl newUrl = getNewFileName(destUrl, dialogText, suggestedFilename, widget);
00223     if (newUrl.isEmpty())
00224         return 0;
00225 
00226     KIO::CopyJob* job = pasteDataAsyncTo(newUrl, ba);
00227     job->ui()->setWindow(widget);
00228     return job;
00229 }
00230 
00231 KIO_EXPORT bool KIO::canPasteMimeSource(const QMimeData* data)
00232 {
00233     return data->hasText() || !extractFormats(data).isEmpty();
00234 }
00235 
00236 #endif
00237 
00238 // The main method for pasting
00239 KIO_EXPORT KIO::Job *KIO::pasteClipboard( const KUrl& destUrl, QWidget* widget, bool move )
00240 {
00241   if ( !destUrl.isValid() ) {
00242     KMessageBox::error( widget, i18n( "Malformed URL\n%1", destUrl.prettyUrl() ) );
00243     return 0;
00244   }
00245 
00246 #ifndef QT_NO_MIMECLIPBOARD
00247   const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00248 
00249   // First check for URLs.
00250   const KUrl::List urls = KUrl::List::fromMimeData(mimeData, KUrl::List::PreferLocalUrls);
00251   if ( !urls.isEmpty() ) {
00252     KIO::Job *res = 0;
00253     if ( move )
00254       res = KIO::move( urls, destUrl );
00255     else
00256       res = KIO::copy( urls, destUrl );
00257     res->ui()->setWindow(widget);
00258 
00259     // If moving, update the clipboard contents with the new locations
00260     if ( move ) {
00261       QApplication::clipboard()->clear();
00262 
00263       KUrl::List newUrls;
00264       for (int i = 0; i < urls.size(); i++) {
00265           KUrl dUrl = destUrl;
00266           dUrl.addPath(urls.at(i).fileName());
00267           newUrls.append(dUrl);
00268       }
00269 
00270       QMimeData* mime = new QMimeData();
00271       newUrls.populateMimeData(mime);
00272       QApplication::clipboard()->setMimeData(mime);
00273     }
00274 
00275     return res;
00276   }
00277   return pasteMimeSource( mimeData, destUrl, QString(), widget, true /*clipboard*/ );
00278 #else
00279   QByteArray ba;
00280   QTextStream txtStream( ba, QIODevice::WriteOnly );
00281 
00282   const QStringList data = QApplication::clipboard()->text().split('\n', QString::SkipEmptyParts);
00283 
00284   KUrl::List urls;
00285   KURLDrag::decode(data, urls);
00286   QStringList::const_iterator end(data.end());
00287   for(QStringList::const_iterator it=data.begin(); it!=end; ++it)
00288       txtStream << *it;
00289   if ( ba.size() == 0 )
00290   {
00291     KMessageBox::sorry(widget, i18n("The clipboard is empty"));
00292     return 0;
00293   }
00294   return pasteDataAsync( destUrl, ba, widget );
00295 #endif
00296 }
00297 
00298 
00299 KIO_EXPORT void KIO::pasteData( const KUrl& u, const QByteArray& _data, QWidget* widget )
00300 {
00301     const KUrl newUrl = getNewFileName( u, QString(), QString(), widget );
00302     // We could use KIO::put here, but that would require a class
00303     // for the slotData call. With NetAccess, we can do a synchronous call.
00304 
00305     if (newUrl.isEmpty())
00306        return;
00307 
00308     KTemporaryFile tempFile;
00309     tempFile.open();
00310     tempFile.write( _data.data(), _data.size() );
00311     tempFile.flush();
00312 
00313     (void) KIO::NetAccess::upload( tempFile.fileName(), newUrl, widget );
00314 }
00315 
00316 // KDE5 TODO: return a KIO::Job*, not a CopyJob*, in case we want to use file_move or a macro job...
00317 // But then the caller needs to know the destUrl too. Return a QPair?
00318 // KDE5: Inline in the only caller, and remove from public API; it's not used anywhere else anymore.
00319 KIO_EXPORT KIO::CopyJob* KIO::pasteDataAsync( const KUrl& u, const QByteArray& _data, QWidget *widget, const QString& text )
00320 {
00321     KUrl newUrl = getNewFileName( u, text, QString(), widget );
00322 
00323     if (newUrl.isEmpty())
00324        return 0;
00325 
00326     KIO::CopyJob* job = pasteDataAsyncTo( newUrl, _data );
00327     job->ui()->setWindow(widget);
00328     return job;
00329 }
00330 
00331 // NOTE: DolphinView::pasteInfo() has a better version of this
00332 // (but which requires KonqFileItemCapabilities)
00333 KIO_EXPORT QString KIO::pasteActionText()
00334 {
00335     const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00336     const KUrl::List urls = KUrl::List::fromMimeData( mimeData );
00337     if ( !urls.isEmpty() ) {
00338         if ( urls.first().isLocalFile() )
00339             return i18np( "&Paste File", "&Paste %1 Files", urls.count() );
00340         else
00341             return i18np( "&Paste URL", "&Paste %1 URLs", urls.count() );
00342     } else if ( !mimeData->formats().isEmpty() ) {
00343         return i18n( "&Paste Clipboard Contents" );
00344     } else {
00345         return QString();
00346     }
00347 }

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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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