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

Skip menu "kdelibs-4.11.5 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