1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include <QtWidgets>
52
53#include "dragwidget.h"
54
55static QLabel *createDragLabel(const QString &text, QWidget *parent)
56{
57 QLabel *label = new QLabel(text, parent);
58 label->setAutoFillBackground(true);
59 label->setFrameShape(QFrame::Panel);
60 label->setFrameShadow(QFrame::Raised);
61 return label;
62}
63
64static QString hotSpotMimeDataKey() { return QStringLiteral("application/x-hotspot"); }
65
66DragWidget::DragWidget(QWidget *parent)
67 : QWidget(parent)
68{
69 QFile dictionaryFile(QStringLiteral(":/dictionary/words.txt"));
70 dictionaryFile.open(QIODevice::ReadOnly);
71 QTextStream inputStream(&dictionaryFile);
72
73 int x = 5;
74 int y = 5;
75
76 while (!inputStream.atEnd()) {
77 QString word;
78 inputStream >> word;
79 if (!word.isEmpty()) {
80 QLabel *wordLabel = createDragLabel(word, this);
81 wordLabel->move(x, y);
82 wordLabel->show();
83 wordLabel->setAttribute(Qt::WA_DeleteOnClose);
84 x += wordLabel->width() + 2;
85 if (x >= 245) {
86 x = 5;
87 y += wordLabel->height() + 2;
88 }
89 }
90 }
91
92 setAcceptDrops(true);
93 setMinimumSize(400, qMax(200, y));
94 setWindowTitle(tr("Draggable Text"));
95}
96
97void DragWidget::dragEnterEvent(QDragEnterEvent *event)
98{
99 if (event->mimeData()->hasText()) {
100 if (event->source() == this) {
101 event->setDropAction(Qt::MoveAction);
102 event->accept();
103 } else {
104 event->acceptProposedAction();
105 }
106 } else {
107 event->ignore();
108 }
109}
110
111void DragWidget::dropEvent(QDropEvent *event)
112{
113 if (event->mimeData()->hasText()) {
114 const QMimeData *mime = event->mimeData();
115 QStringList pieces = mime->text().split(QRegularExpression(QStringLiteral("\\s+")),
116 Qt::SkipEmptyParts);
117 QPoint position = event->position().toPoint();
118 QPoint hotSpot;
119
120 QByteArrayList hotSpotPos = mime->data(hotSpotMimeDataKey()).split(' ');
121 if (hotSpotPos.size() == 2) {
122 hotSpot.setX(hotSpotPos.first().toInt());
123 hotSpot.setY(hotSpotPos.last().toInt());
124 }
125
126 for (const QString &piece : pieces) {
127 QLabel *newLabel = createDragLabel(piece, this);
128 newLabel->move(position - hotSpot);
129 newLabel->show();
130 newLabel->setAttribute(Qt::WA_DeleteOnClose);
131
132 position += QPoint(newLabel->width(), 0);
133 }
134
135 if (event->source() == this) {
136 event->setDropAction(Qt::MoveAction);
137 event->accept();
138 } else {
139 event->acceptProposedAction();
140 }
141 } else {
142 event->ignore();
143 }
144 for (QWidget *widget : findChildren<QWidget *>()) {
145 if (!widget->isVisible())
146 widget->deleteLater();
147 }
148}
149
150void DragWidget::mousePressEvent(QMouseEvent *event)
151{
152 QLabel *child = qobject_cast<QLabel*>(childAt(event->position().toPoint()));
153 if (!child)
154 return;
155
156 QPoint hotSpot = event->position().toPoint() - child->pos();
157
158 QMimeData *mimeData = new QMimeData;
159 mimeData->setText(child->text());
160 mimeData->setData(hotSpotMimeDataKey(),
161 QByteArray::number(hotSpot.x()) + ' ' + QByteArray::number(hotSpot.y()));
162
163 qreal dpr = window()->windowHandle()->devicePixelRatio();
164 QPixmap pixmap(child->size() * dpr);
165 pixmap.setDevicePixelRatio(dpr);
166 child->render(&pixmap);
167
168 QDrag *drag = new QDrag(this);
169 drag->setMimeData(mimeData);
170 drag->setPixmap(pixmap);
171 drag->setHotSpot(hotSpot);
172
173 Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
174
175 if (dropAction == Qt::MoveAction)
176 child->close();
177}
178