1
/**************************************************************************
3
* Copyright 2014 Canonical Ltd.
4
* Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
6
* You may use this file under the terms of the BSD license as follows:
8
* "Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions are
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* * Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in
15
* the documentation and/or other materials provided with the
17
* * Neither the name of Nemo Mobile nor the names of its contributors
18
* may be used to endorse or promote products derived from this
19
* software without specific prior written permission.
21
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37
#include "clipboard.h"
40
#include <QApplication>
45
static QLatin1String GNOME_COPIED_MIME_TYPE ("x-special/gnome-copied-files");
46
static QLatin1String KDE_CUT_MIME_TYPE ("application/x-kde-cutselection");
49
int DirModelMimeData::m_instances = 0;
50
DirModelMimeData* DirModelMimeData::m_globalMimeData = 0;
53
bool DirModelMimeData::hasFormat ( const QString & mimeType ) const
56
if ( mimeType == KDE_CUT_MIME_TYPE )
62
ret = m_formats.contains(mimeType);
67
//===============================================================================================
69
* \brief DirModelMimeData::DirModelMimeData
71
DirModelMimeData::DirModelMimeData() :
75
m_formats.append("text/uri-list");
76
m_formats.append(GNOME_COPIED_MIME_TYPE);
77
m_formats.append("text/plain");
78
m_formats.append("COMPOUND_TEXT");
79
m_formats.append("TARGETS");
80
m_formats.append("MULTIPLE");
81
m_formats.append("TIMESTAMP");
82
m_formats.append("SAVE_TARGETS");
86
qDebug() << Q_FUNC_INFO << this << "instances" << m_instances;
93
DirModelMimeData::~DirModelMimeData()
97
qDebug() << Q_FUNC_INFO << this << "instances" << m_instances
98
<< "m_globalMimeData" << m_globalMimeData;
100
if (m_instances == 1 && m_globalMimeData)
102
DirModelMimeData * tmp = m_globalMimeData;
103
m_globalMimeData = 0;
108
//===============================================================================================
110
* \brief DirModelMimeData::gnomeUrls
116
DirModelMimeData::gnomeUrls(const QMimeData * mime,
117
ClipboardOperation& operation)
120
if (mime->hasFormat(GNOME_COPIED_MIME_TYPE))
122
QByteArray bytes = mime->data(GNOME_COPIED_MIME_TYPE);
123
QList<QString> d = QString(bytes).split(QLatin1String("\n"),
124
QString::SkipEmptyParts);
125
operation = ClipboardCopy;
128
if (d.at(0).trimmed().startsWith(QLatin1String("cut")))
130
operation = ClipboardCut;
132
for (int counter= 1; counter < d.count(); counter++)
134
urls.append(d.at(counter).trimmed());
141
//===============================================================================================
143
* \brief DirModelMimeData::clipBoardOperation()
147
ClipboardOperation DirModelMimeData::clipBoardOperation()
149
ClipboardOperation op = ClipboardCopy;
150
m_appMime = clipboardMimeData();
153
//first check for GNOME clipboard format, op comes with Copy/Cut
154
if (gnomeUrls(m_appMime, op).count() == 0)
155
{ // there is no gnome format, tries KDE format
156
QStringList formats = m_appMime->formats();
157
int f = formats.count();
160
const QString &mi = formats.at(f);
161
if(mi.startsWith(QLatin1String("application/x-kde")) )
163
if (mi.contains(QLatin1String("cut")))
176
//===============================================================================================
178
* \brief DirModelMimeData::setIntoClipboard
180
* Try to put data in the global cliboard
183
* On mobile devices clipboard might not work, in this case a local Clipboard is simulated
188
* \return who is owner of clipboard data
190
DirModelMimeData::ClipBoardDataOwner
191
DirModelMimeData::setIntoClipboard(const QStringList &files, const QString& path, ClipboardOperation operation)
193
static bool firstTime = true;
194
DirModelMimeData::ClipBoardDataOwner ret = Nobody;
195
QClipboard *clipboard = QApplication::clipboard();
199
DirModelMimeData *mime = m_globalMimeData ? m_globalMimeData
200
: new DirModelMimeData();
201
if (mime->fillClipboard(files, path, operation))
203
clipboard->setMimeData(mime);
204
//it looks like some mobile devices does not have X or Clipboard does work for other reason
205
//in this case we simulate our own clipboard, the QClipboard::dataChanged() signal is also
206
//checked in \ref Clipboard::storeOnClipboard()
210
if (!m_globalMimeData && !testClipboardContent(files, path))
212
qWarning() << "QClipboard does not work, using own QMimeData storage";
213
m_globalMimeData = mime;
217
qDebug() << Q_FUNC_INFO << "mime" << mime
218
<< "own Clipboard Mime Data" << m_globalMimeData;
222
if (m_globalMimeData != mime)
226
//check if it is necessary to send notification about Clipboard changed
227
if (m_globalMimeData)
237
bool DirModelMimeData::fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation)
240
int index = m_formats.indexOf(KDE_CUT_MIME_TYPE);
241
if (index != -1 && operation != ClipboardCut)
243
m_formats.removeAt(index);
246
if (operation == ClipboardCut)
248
m_formats.append(KDE_CUT_MIME_TYPE);
252
m_gnomeData += operation == ClipboardCut ?
253
QLatin1String("cut") :
254
QLatin1String("copy");
255
QStringList fullPaths = makeFullPath(files, path);
256
for(int counter = 0; counter < fullPaths.count(); counter++)
258
QUrl item = QUrl::fromLocalFile(fullPaths.at((counter)));
260
m_gnomeData += QLatin1Char('\n') + item.toEncoded() ;
262
if (m_urls.count() > 0)
264
setData(GNOME_COPIED_MIME_TYPE, m_gnomeData);
270
// emit error( QObject::tr("Item does not exist"), item);
275
//===============================================================================================
277
* \brief DirModelMimeData::clipboardMimeData
280
const QMimeData *DirModelMimeData::clipboardMimeData()
282
const QMimeData *ret = 0;
283
QClipboard *clipboard = QApplication::clipboard();
284
if (m_globalMimeData)
286
ret = m_globalMimeData;
291
ret = clipboard->mimeData();
294
qDebug() << Q_FUNC_INFO << "clipboard" << clipboard
295
<< "m_ownClipboardMimeData" << m_globalMimeData
296
<< "clipboard->mimeData()" << ret;
301
//===============================================================================================
303
* \brief DirModelMimeData::localUrls
307
DirModelMimeData::localUrls(ClipboardOperation& operation)
309
m_appMime = clipboardMimeData();
311
//it may have external urls
315
if (m_appMime->hasUrls())
317
urls = m_appMime->urls();
318
operation = clipBoardOperation();
322
urls = gnomeUrls(m_appMime, operation);
324
for (int counter=0; counter < urls.count(); counter++)
326
if (urls.at(counter).toString().startsWith(QLatin1String("file://")))
328
paths.append(urls.at(counter).toLocalFile());
333
qDebug() << Q_FUNC_INFO << paths;
339
//===============================================================================================
341
* \brief DirModelMimeData::testClipboardContent() Gets the clipboard content and compare with data previously stored
344
* \return true if clipboard has content and it matches data previously stored
346
bool DirModelMimeData::testClipboardContent(const QStringList &files, const QString &path)
349
ClipboardOperation tmpOperation;
350
QStringList expectedList = makeFullPath(files,path);
351
QStringList realList = localUrls(tmpOperation);
352
if (realList == expectedList)
358
qWarning() << Q_FUNC_INFO << "FAILED, Clipboard does not work";
363
//===============================================================================================
365
* \brief DirModelMimeData::makeFullPath() Just creates a fulpath file list when they do exist
368
* \return the list itself
370
QStringList DirModelMimeData::makeFullPath(const QStringList& files, const QString &path)
372
QStringList fullPathnameList;
374
for(int counter = 0; counter < files.count(); counter++)
376
const QString& item = files.at(counter);
378
if (!fi.isAbsolute())
380
fi.setFile(path + QDir::separator() + item);
384
fullPathnameList.append(fi.absoluteFilePath());
387
return fullPathnameList;
391
//===========================================================================
393
//===========================================================================
394
Clipboard::Clipboard(QObject *parent):
396
, m_mimeData ( new DirModelMimeData() )
397
, m_clipboardModifiedByOther(false)
399
QClipboard *clipboard = QApplication::clipboard();
401
connect(clipboard, SIGNAL(dataChanged()), this, SIGNAL(clipboardChanged()));
402
connect(clipboard, SIGNAL(dataChanged()), this, SLOT(onClipboardChanged()));
406
Clipboard::~Clipboard()
411
//================================================================================
413
* \brief Clipboard::clipboardHasChanged() used to identify if the clipboard changed during a Cut operation
415
* \sa \ref endCurrentAction()
417
void Clipboard::onClipboardChanged()
419
m_clipboardModifiedByOther = true;
423
//==================================================================
425
* \brief Clipboard::storeOnClipboard() store data on Clipboard
426
* \param pathnames files list
427
* \param op \ref ClipboardOperation as \ref ClipboardCopy or \ref ClipboardCut
429
* Stores data on clipboard by calling \ref DirModelMimeData::setIntoClipboard() which uses Qt class QClipboard
430
* It is expected that QClipboard class emits the dataChanged() signal when a new content is set into it,
431
* if it does we caught that signal in \ref clipboardHasChanged() which sets \ref m_clipboardModifiedByOther to true.
433
void Clipboard::storeOnClipboard(const QStringList &names, ClipboardOperation op, const QString& curPath)
436
qDebug() << Q_FUNC_INFO << names << "ClipboardOperation" << op;
438
DirModelMimeData::ClipBoardDataOwner owner =
439
m_mimeData->setIntoClipboard(names, curPath, op);
440
if (owner == DirModelMimeData::MySelf || !m_clipboardModifiedByOther)
442
emit clipboardChanged();
444
m_clipboardModifiedByOther = false;
447
//===============================================================================================
449
* \brief Clipboard::copy
452
void Clipboard::copy(const QStringList &names, const QString& path)
454
storeOnClipboard(names, ClipboardCopy, path);
457
//===============================================================================================
459
* \brief Clipboard::cut
462
void Clipboard::cut(const QStringList &names, const QString &path)
464
storeOnClipboard(names, ClipboardCut, path);
468
//=======================================================
470
* \brief Clipboard::clipboardLocalUrlsCounter
473
int Clipboard::clipboardLocalUrlsCounter()
475
ClipboardOperation operation;
476
return m_mimeData->localUrls(operation).count();
480
//=======================================================
482
* \brief Clipboard::paste
486
QStringList Clipboard::paste(ClipboardOperation &operation)
488
QStringList items = m_mimeData->localUrls(operation);
489
if (operation == ClipboardCut)
491
//this must still be false when cut finishes to change the clipboard to the target
492
m_clipboardModifiedByOther = false;