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"
38
#include "locationurl.h"
41
#include <QApplication>
46
static QLatin1String GNOME_COPIED_MIME_TYPE ("x-special/gnome-copied-files");
47
static QLatin1String KDE_CUT_MIME_TYPE ("application/x-kde-cutselection");
50
int DirModelMimeData::m_instances = 0;
51
DirModelMimeData* DirModelMimeData::m_globalMimeData = 0;
54
bool DirModelMimeData::hasFormat ( const QString & mimeType ) const
57
if ( mimeType == KDE_CUT_MIME_TYPE )
63
ret = m_formats.contains(mimeType);
68
//===============================================================================================
70
* \brief DirModelMimeData::DirModelMimeData
72
DirModelMimeData::DirModelMimeData() :
76
m_formats.append("text/uri-list");
77
m_formats.append(GNOME_COPIED_MIME_TYPE);
78
m_formats.append("text/plain");
79
m_formats.append("COMPOUND_TEXT");
80
m_formats.append("TARGETS");
81
m_formats.append("MULTIPLE");
82
m_formats.append("TIMESTAMP");
83
m_formats.append("SAVE_TARGETS");
87
qDebug() << Q_FUNC_INFO << this << "instances" << m_instances;
94
DirModelMimeData::~DirModelMimeData()
98
qDebug() << Q_FUNC_INFO << this << "instances" << m_instances
99
<< "m_globalMimeData" << m_globalMimeData;
101
if (m_instances == 1 && m_globalMimeData)
103
DirModelMimeData * tmp = m_globalMimeData;
104
m_globalMimeData = 0;
109
//===============================================================================================
111
* \brief DirModelMimeData::gnomeUrls
117
DirModelMimeData::gnomeUrls(const QMimeData * mime,
118
ClipboardOperation& operation)
121
if (mime->hasFormat(GNOME_COPIED_MIME_TYPE))
123
QByteArray bytes = mime->data(GNOME_COPIED_MIME_TYPE);
124
QList<QString> d = QString(bytes).split(QLatin1String("\n"),
125
QString::SkipEmptyParts);
126
operation = ClipboardCopy;
129
if (d.at(0).trimmed().startsWith(QLatin1String("cut")))
131
operation = ClipboardCut;
133
for (int counter= 1; counter < d.count(); counter++)
135
urls.append(d.at(counter).trimmed());
142
//===============================================================================================
144
* \brief DirModelMimeData::clipBoardOperation()
148
ClipboardOperation DirModelMimeData::clipBoardOperation()
150
ClipboardOperation op = ClipboardCopy;
151
m_appMime = clipboardMimeData();
154
//first check for GNOME clipboard format, op comes with Copy/Cut
155
if (gnomeUrls(m_appMime, op).count() == 0)
156
{ // there is no gnome format, tries KDE format
157
QStringList formats = m_appMime->formats();
158
int f = formats.count();
161
const QString &mi = formats.at(f);
162
if(mi.startsWith(QLatin1String("application/x-kde")) )
164
if (mi.contains(QLatin1String("cut")))
177
//===============================================================================================
179
* \brief DirModelMimeData::setIntoClipboard
181
* Try to put data in the global cliboard
184
* On mobile devices clipboard might not work, in this case a local Clipboard is simulated
189
* \return who is owner of clipboard data
191
DirModelMimeData::ClipBoardDataOwner
192
DirModelMimeData::setIntoClipboard(const QStringList &files, const QString& path, ClipboardOperation operation)
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
static bool firstTime = true;
204
clipboard->setMimeData(mime);
205
//it looks like some mobile devices does not have X or Clipboard does work for other reason
206
//in this case we simulate our own clipboard, the QClipboard::dataChanged() signal is also
207
//checked in \ref Clipboard::storeOnClipboard()
211
if (!m_globalMimeData && !testClipboardContent(files, path))
213
qWarning() << "QClipboard does not work, using own QMimeData storage";
214
m_globalMimeData = mime;
218
qDebug() << Q_FUNC_INFO << "mime" << mime
219
<< "own Clipboard Mime Data" << m_globalMimeData;
223
if (m_globalMimeData != mime)
227
//check if it is necessary to send notification about Clipboard changed
228
if (m_globalMimeData)
238
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(fullPaths.at((counter)));
259
if (item.scheme().isEmpty() && !item.isLocalFile())
261
item = QUrl::fromLocalFile(fullPaths.at((counter)));
263
if (LocationUrl::isSupportedUrl(item))
266
m_gnomeData += QLatin1Char('\n') + item.toEncoded() ;
269
bool ret = m_urls.count() > 0;
272
setData(GNOME_COPIED_MIME_TYPE, m_gnomeData);
278
//===============================================================================================
280
* \brief DirModelMimeData::clipboardMimeData
283
const QMimeData *DirModelMimeData::clipboardMimeData()
285
const QMimeData *ret = 0;
286
QClipboard *clipboard = QApplication::clipboard();
287
if (m_globalMimeData)
289
ret = m_globalMimeData;
294
ret = clipboard->mimeData();
297
qDebug() << Q_FUNC_INFO << "clipboard" << clipboard
298
<< "m_ownClipboardMimeData" << m_globalMimeData
299
<< "clipboard->mimeData()" << ret;
304
//===============================================================================================
306
* \brief DirModelMimeData::storedUrls
307
* \return the list of Urls stored in the Clipboard
310
DirModelMimeData::storedUrls(ClipboardOperation& operation)
312
m_appMime = clipboardMimeData();
314
//it may have external urls
318
if (m_appMime->hasUrls())
320
urls = m_appMime->urls();
321
operation = clipBoardOperation();
325
urls = gnomeUrls(m_appMime, operation);
327
for (int counter=0; counter < urls.count(); counter++)
329
if (LocationUrl::isSupportedUrl(urls.at(counter)))
331
if (urls.at(counter).isLocalFile())
333
paths.append(urls.at(counter).toLocalFile());
337
paths.append(urls.at(counter).toString());
343
qDebug() << Q_FUNC_INFO << paths;
349
//===============================================================================================
351
* \brief DirModelMimeData::testClipboardContent() Gets the clipboard content and compare with data previously stored
354
* \return true if clipboard has content and it matches data previously stored
356
bool DirModelMimeData::testClipboardContent(const QStringList &files, const QString &path)
359
ClipboardOperation tmpOperation;
360
QStringList expectedList = makeFullPath(files,path);
361
QStringList realList = storedUrls(tmpOperation);
362
if (realList == expectedList)
368
qWarning() << Q_FUNC_INFO << "FAILED, Clipboard does not work";
373
//===============================================================================================
375
* \brief DirModelMimeData::makeFullPath() Just creates a fulpath file list if files are relative
378
* \return the list itself
380
QStringList DirModelMimeData::makeFullPath(const QStringList& files, const QString &path)
382
QStringList fullPathnameList;
383
if (files.count() > 0)
385
if (path.length() > 0 && !files.at(0).startsWith(path))
387
for(int counter = 0; counter < files.count(); counter++)
389
fullPathnameList.append(path + QDir::separator() + files.at(counter));
394
//they already have a full path
395
fullPathnameList = files;
398
return fullPathnameList;
402
//===========================================================================
404
//===========================================================================
405
Clipboard::Clipboard(QObject *parent):
407
, m_mimeData ( new DirModelMimeData() )
408
, m_clipboardModifiedByOther(false)
410
QClipboard *clipboard = QApplication::clipboard();
412
connect(clipboard, SIGNAL(dataChanged()), this, SIGNAL(clipboardChanged()));
413
connect(clipboard, SIGNAL(dataChanged()), this, SLOT(onClipboardChanged()));
417
Clipboard::~Clipboard()
422
//================================================================================
424
* \brief Clipboard::clipboardHasChanged() used to identify if the clipboard changed during a Cut operation
426
* \sa \ref endCurrentAction()
428
void Clipboard::onClipboardChanged()
430
m_clipboardModifiedByOther = true;
434
//==================================================================
436
* \brief Clipboard::storeOnClipboard() store data on Clipboard
437
* \param pathnames files list
438
* \param op \ref ClipboardOperation as \ref ClipboardCopy or \ref ClipboardCut
440
* Stores data on clipboard by calling \ref DirModelMimeData::setIntoClipboard() which uses Qt class QClipboard
441
* It is expected that QClipboard class emits the dataChanged() signal when a new content is set into it,
442
* if it does we caught that signal in \ref clipboardHasChanged() which sets \ref m_clipboardModifiedByOther to true.
444
void Clipboard::storeOnClipboard(const QStringList &names, ClipboardOperation op, const QString& curPath)
447
qDebug() << Q_FUNC_INFO << names << "ClipboardOperation" << op;
449
DirModelMimeData::ClipBoardDataOwner owner =
450
m_mimeData->setIntoClipboard(names, curPath, op);
451
if (owner == DirModelMimeData::MySelf || !m_clipboardModifiedByOther)
453
emit clipboardChanged();
455
m_clipboardModifiedByOther = false;
458
//===============================================================================================
460
* \brief Clipboard::copy
463
void Clipboard::copy(const QStringList &names, const QString& path)
465
storeOnClipboard(names, ClipboardCopy, path);
468
//===============================================================================================
470
* \brief Clipboard::cut
473
void Clipboard::cut(const QStringList &names, const QString &path)
475
storeOnClipboard(names, ClipboardCut, path);
479
//=======================================================
481
* \brief Clipboard::storedUrlsCounter
484
int Clipboard::storedUrlsCounter()
486
ClipboardOperation operation;
487
return m_mimeData->storedUrls(operation).count();
491
//=======================================================
493
* \brief Clipboard::paste
497
QStringList Clipboard::paste(ClipboardOperation &operation)
499
QStringList items = m_mimeData->storedUrls(operation);
500
if (operation == ClipboardCut)
502
//this must still be false when cut finishes to change the clipboard to the target
503
m_clipboardModifiedByOther = false;
509
* \brief Clears clipboard entries
511
void Clipboard::clear()
513
qDebug() << Q_FUNC_INFO << "Clearing clipboard";
514
storeOnClipboard(QStringList(), ClipboardCopy, "");