• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.2 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kio
paste.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 David Faure <faure@kde.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 #include "paste.h"
20 #include "pastedialog.h"
21 
22 #include "kio/job.h"
23 #include "kio/copyjob.h"
24 #include "kio/deletejob.h"
25 #include "kio/global.h"
26 #include "kio/netaccess.h"
27 #include "kio/renamedialog.h"
28 #include "kio/kprotocolmanager.h"
29 #include "jobuidelegate.h"
30 
31 #include <kurl.h>
32 #include <kdebug.h>
33 #include <klocale.h>
34 #include <kinputdialog.h>
35 #include <kmessagebox.h>
36 #include <kmimetype.h>
37 #include <ktemporaryfile.h>
38 
39 #include <QtGui/QApplication>
40 #include <QtGui/QClipboard>
41 #include <QMimeData>
42 
43 static bool decodeIsCutSelection(const QMimeData *mimeData)
44 {
45  const QByteArray data = mimeData->data("application/x-kde-cutselection");
46  return data.isEmpty() ? false : data.at(0) == '1';
47 }
48 
49 // This could be made a public method, if there's a need for pasting only urls
50 // and not random data.
61 //KIO_EXPORT Job *pasteClipboardUrls(const KUrl& destDir, JobFlags flags = DefaultFlags);
62 static KIO::Job *pasteClipboardUrls(const QMimeData* mimeData, const KUrl& destDir, KIO::JobFlags flags = KIO::DefaultFlags)
63 {
64  const KUrl::List urls = KUrl::List::fromMimeData(mimeData, KUrl::List::PreferLocalUrls);
65  if (!urls.isEmpty()) {
66  const bool move = decodeIsCutSelection(mimeData);
67  KIO::Job *job = 0;
68  if (move)
69  job = KIO::move(urls, destDir, flags);
70  else
71  job = KIO::copy(urls, destDir, flags);
72 
73  // If moving, update the clipboard contents with the new locations
74  if (move) {
75  QApplication::clipboard()->clear();
76 
77  KUrl::List newUrls;
78  Q_FOREACH(const KUrl& url, urls) {
79  KUrl dUrl = destDir;
80  dUrl.addPath(url.fileName());
81  newUrls.append(dUrl);
82  }
83 
84  QMimeData* mime = new QMimeData();
85  newUrls.populateMimeData(mime);
86  QApplication::clipboard()->setMimeData(mime);
87  }
88  return job;
89  }
90  return 0;
91 }
92 
93 static KUrl getNewFileName( const KUrl &u, const QString& text, const QString& suggestedFileName, QWidget *widget, bool delIfOverwrite )
94 {
95  bool ok;
96  QString dialogText( text );
97  if ( dialogText.isEmpty() )
98  dialogText = i18n( "Filename for clipboard content:" );
99  QString file = KInputDialog::getText( QString(), dialogText, suggestedFileName, &ok, widget );
100  if ( !ok )
101  return KUrl();
102 
103  KUrl myurl(u);
104  myurl.addPath( file );
105 
106  // Check for existing destination file.
107  // When we were using CopyJob, we couldn't let it do that (would expose
108  // an ugly tempfile name as the source URL)
109  // And now we're using a put job anyway, no destination checking included.
110  if (KIO::NetAccess::exists(myurl, KIO::NetAccess::DestinationSide, widget))
111  {
112  kDebug(7007) << "Paste will overwrite file. Prompting...";
113  KIO::RenameDialog_Result res = KIO::R_OVERWRITE;
114 
115  KIO::RenameDialog dlg( widget,
116  i18n("File Already Exists"),
117  u.pathOrUrl(),
118  myurl.pathOrUrl(),
119  (KIO::RenameDialog_Mode) (KIO::M_OVERWRITE | KIO::M_SINGLE) );
120  res = static_cast<KIO::RenameDialog_Result>(dlg.exec());
121 
122  if ( res == KIO::R_RENAME )
123  {
124  myurl = dlg.newDestUrl();
125  }
126  else if ( res == KIO::R_CANCEL )
127  {
128  return KUrl();
129  } else if (res == KIO::R_OVERWRITE)
130  {
131  // Old hack. With the put job we just pass Overwrite.
132  if (delIfOverwrite) {
133  // Ideally we would just pass KIO::Overwrite to the job in pasteDataAsyncTo.
134  // But 1) CopyJob doesn't support that (it wouldn't really apply to multiple files) [not true anymore]
135  // 2) we can't use file_move because CopyJob* is everywhere in the API (see TODO)
136  // But well the simpler is really to delete the dest:
137  KIO::Job* delJob = KIO::del(myurl);
138  delJob->exec();
139  }
140  }
141  }
142 
143  return myurl;
144 }
145 
146 // Old solution
147 // The final step: write _data to tempfile and move it to newUrl
148 static KIO::CopyJob* pasteDataAsyncTo( const KUrl& newUrl, const QByteArray& _data )
149 {
150  // ### Bug: because we move from a tempfile to the destination,
151  // if the user does "Undo" then we won't ask for confirmation, and we'll
152  // move back to a tempfile, instead of just deleting.
153  // A KIO::storedPut would be better but FileUndoManager would need to support it first.
154  KTemporaryFile tempFile;
155  tempFile.setAutoRemove(false);
156  tempFile.open();
157  tempFile.write(_data.data(), _data.size());
158  tempFile.flush();
159  KUrl origUrl(tempFile.fileName());
160  return KIO::move(origUrl, newUrl);
161 }
162 
163 // New solution
164 static KIO::Job* putDataAsyncTo(const KUrl& url, const QByteArray& data, QWidget* widget, KIO::JobFlags flags)
165 {
166  KIO::Job* job = KIO::storedPut(data, url, -1, flags);
167  job->ui()->setWindow(widget);
168  return job;
169 }
170 
171 static QByteArray chooseFormatAndUrl(const KUrl& u, const QMimeData* mimeData,
172  const QStringList& formats,
173  const QString& text,
174  const QString& suggestedFileName,
175  QWidget* widget,
176  bool clipboard,
177  KUrl* newUrl)
178 {
179  QStringList formatLabels;
180  for ( int i = 0; i < formats.size(); ++i ) {
181  const QString& fmt = formats[i];
182  KMimeType::Ptr mime = KMimeType::mimeType(fmt, KMimeType::ResolveAliases);
183  if (mime)
184  formatLabels.append( i18n("%1 (%2)", mime->comment(), fmt) );
185  else
186  formatLabels.append( fmt );
187  }
188 
189  QString dialogText( text );
190  if ( dialogText.isEmpty() )
191  dialogText = i18n( "Filename for clipboard content:" );
192  //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
193  KIO::PasteDialog dlg( QString::null, dialogText, suggestedFileName, formatLabels, widget, clipboard ); //krazy:exclude=nullstrassign
194 
195  if ( dlg.exec() != KDialog::Accepted )
196  return QByteArray();
197 
198  if ( clipboard && dlg.clipboardChanged() ) {
199  KMessageBox::sorry( widget,
200  i18n( "The clipboard has changed since you used 'paste': "
201  "the chosen data format is no longer applicable. "
202  "Please copy again what you wanted to paste." ) );
203  return QByteArray();
204  }
205 
206  const QString result = dlg.lineEditText();
207  const QString chosenFormat = formats[ dlg.comboItem() ];
208 
209  kDebug() << " result=" << result << " chosenFormat=" << chosenFormat;
210  *newUrl = KUrl( u );
211  newUrl->addPath( result );
212  // if "data" came from QClipboard, then it was deleted already - by a nice 0-seconds timer
213  // In that case, get it again. Let's hope the user didn't copy something else meanwhile :/
214  // #### QT4/KDE4 TODO: check that this is still the case
215  if ( clipboard ) {
216  mimeData = QApplication::clipboard()->mimeData();
217  }
218  const QByteArray ba = mimeData->data( chosenFormat );
219  return ba;
220 }
221 
222 static QStringList extractFormats(const QMimeData* mimeData)
223 {
224  QStringList formats;
225  const QStringList allFormats = mimeData->formats();
226  Q_FOREACH(const QString& format, allFormats) {
227  if (format == QLatin1String("application/x-qiconlist")) // see QIconDrag
228  continue;
229  if (format == QLatin1String("application/x-kde-cutselection")) // see KonqDrag
230  continue;
231  if (format == QLatin1String("application/x-kde-suggestedfilename"))
232  continue;
233  if (format.startsWith(QLatin1String("application/x-qt-"))) // Qt-internal
234  continue;
235  if (format.startsWith(QLatin1String("x-kmail-drag/"))) // app-internal
236  continue;
237  if (!format.contains(QLatin1Char('/'))) // e.g. TARGETS, MULTIPLE, TIMESTAMP
238  continue;
239  formats.append(format);
240  }
241  return formats;
242 }
243 
244 // The [old] main method for dropping
245 KIO::CopyJob* KIO::pasteMimeSource( const QMimeData* mimeData, const KUrl& destUrl,
246  const QString& dialogText, QWidget* widget, bool clipboard )
247 {
248  QByteArray ba;
249 
250  const QString suggestedFilename = QString::fromUtf8(mimeData->data("application/x-kde-suggestedfilename"));
251 
252  // Now check for plain text
253  // We don't want to display a mimetype choice for a QTextDrag, those mimetypes look ugly.
254  if ( mimeData->hasText() )
255  {
256  ba = mimeData->text().toLocal8Bit(); // encoding OK?
257  }
258  else
259  {
260  const QStringList formats = extractFormats(mimeData);
261  if ( formats.size() == 0 )
262  return 0;
263 
264  if ( formats.size() > 1 ) {
265  KUrl newUrl;
266  ba = chooseFormatAndUrl(destUrl, mimeData, formats, dialogText, suggestedFilename, widget, clipboard, &newUrl);
267  KIO::CopyJob* job = pasteDataAsyncTo(newUrl, ba);
268  job->ui()->setWindow(widget);
269  return job;
270  }
271  ba = mimeData->data( formats.first() );
272  }
273  if ( ba.isEmpty() )
274  {
275  KMessageBox::sorry( widget, i18n("The clipboard is empty") );
276  return 0;
277  }
278 
279  const KUrl newUrl = getNewFileName(destUrl, dialogText, suggestedFilename, widget, true);
280  if (newUrl.isEmpty())
281  return 0;
282 
283  KIO::CopyJob* job = pasteDataAsyncTo(newUrl, ba);
284  job->ui()->setWindow(widget);
285  return job;
286 }
287 
288 KIO_EXPORT bool KIO::canPasteMimeSource(const QMimeData* data)
289 {
290  return data->hasText() || !extractFormats(data).isEmpty();
291 }
292 
293 KIO::Job* pasteMimeDataImpl(const QMimeData* mimeData, const KUrl& destUrl,
294  const QString& dialogText, QWidget* widget,
295  bool clipboard)
296 {
297  QByteArray ba;
298  const QString suggestedFilename = QString::fromUtf8(mimeData->data("application/x-kde-suggestedfilename"));
299 
300  // Now check for plain text
301  // We don't want to display a mimetype choice for a QTextDrag, those mimetypes look ugly.
302  if (mimeData->hasText()) {
303  ba = mimeData->text().toLocal8Bit(); // encoding OK?
304  } else {
305  const QStringList formats = extractFormats(mimeData);
306  if (formats.isEmpty()) {
307  return 0;
308  } else if (formats.size() > 1) {
309  KUrl newUrl;
310  ba = chooseFormatAndUrl(destUrl, mimeData, formats, dialogText, suggestedFilename, widget, clipboard, &newUrl);
311  if (ba.isEmpty()) {
312  return 0;
313  }
314  return putDataAsyncTo(newUrl, ba, widget, KIO::Overwrite);
315  }
316  ba = mimeData->data(formats.first());
317  }
318  if (ba.isEmpty()) {
319  return 0;
320  }
321 
322  const KUrl newUrl = getNewFileName(destUrl, dialogText, suggestedFilename, widget, false);
323  if (newUrl.isEmpty())
324  return 0;
325 
326  return putDataAsyncTo(newUrl, ba, widget, KIO::Overwrite);
327 }
328 
329 // The main method for pasting
330 KIO_EXPORT KIO::Job *KIO::pasteClipboard( const KUrl& destUrl, QWidget* widget, bool move )
331 {
332  Q_UNUSED(move);
333 
334  if ( !destUrl.isValid() ) {
335  KMessageBox::error( widget, i18n( "Malformed URL\n%1", destUrl.prettyUrl() ) );
336  return 0;
337  }
338 
339  // TODO: if we passed mimeData as argument, we could write unittests that don't
340  // mess up the clipboard and that don't need QtGui.
341  const QMimeData *mimeData = QApplication::clipboard()->mimeData();
342 
343  if (KUrl::List::canDecode(mimeData)) {
344  // We can ignore the bool move, KIO::paste decodes it
345  KIO::Job* job = pasteClipboardUrls(mimeData, destUrl);
346  if (job) {
347  job->ui()->setWindow(widget);
348  return job;
349  }
350  }
351 
352  return pasteMimeDataImpl(mimeData, destUrl, QString(), widget, true /*clipboard*/);
353 }
354 
355 
356 KIO_EXPORT void KIO::pasteData(const KUrl& u, const QByteArray& data, QWidget* widget)
357 {
358  const KUrl newUrl = getNewFileName(u, QString(), QString(), widget, false);
359  if (newUrl.isEmpty())
360  return;
361 
362  KIO::Job* job = putDataAsyncTo(newUrl, data, widget, KIO::Overwrite);
363  KIO::NetAccess::synchronousRun(job, widget);
364 }
365 
366 // KDE5: remove
367 KIO_EXPORT KIO::CopyJob* KIO::pasteDataAsync( const KUrl& u, const QByteArray& _data, QWidget *widget, const QString& text )
368 {
369  KUrl newUrl = getNewFileName(u, text, QString(), widget, true);
370 
371  if (newUrl.isEmpty())
372  return 0;
373 
374  KIO::CopyJob* job = pasteDataAsyncTo( newUrl, _data );
375  job->ui()->setWindow(widget);
376  return job;
377 }
378 
379 // NOTE: DolphinView::pasteInfo() has a better version of this
380 // (but which requires KonqFileItemCapabilities)
381 KIO_EXPORT QString KIO::pasteActionText()
382 {
383  const QMimeData *mimeData = QApplication::clipboard()->mimeData();
384  const KUrl::List urls = KUrl::List::fromMimeData( mimeData );
385  if ( !urls.isEmpty() ) {
386  if ( urls.first().isLocalFile() )
387  return i18np( "&Paste File", "&Paste %1 Files", urls.count() );
388  else
389  return i18np( "&Paste URL", "&Paste %1 URLs", urls.count() );
390  } else if ( !mimeData->formats().isEmpty() ) {
391  return i18n( "&Paste Clipboard Contents" );
392  } else {
393  return QString();
394  }
395 }
396 
397 // The [new] main method for dropping
398 KIO_EXPORT KIO::Job* KIO::pasteMimeData(const QMimeData* mimeData, const KUrl& destUrl,
399  const QString& dialogText, QWidget* widget)
400 {
401  return pasteMimeDataImpl(mimeData, destUrl, dialogText, widget, false /*not clipboard*/);
402 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Apr 16 2013 21:04:58 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

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

kdelibs-4.10.2 API Reference

Skip menu "kdelibs-4.10.2 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal