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 "piecesmodel.h" |
52 | |
53 | #include <QIcon> |
54 | #include <QMimeData> |
55 | #include <QRandomGenerator> |
56 | |
57 | PiecesModel::PiecesModel(int pieceSize, QObject *parent) |
58 | : QAbstractListModel(parent), m_PieceSize(pieceSize) |
59 | { |
60 | } |
61 | |
62 | QVariant PiecesModel::data(const QModelIndex &index, int role) const |
63 | { |
64 | if (!index.isValid()) |
65 | return QVariant(); |
66 | |
67 | if (role == Qt::DecorationRole) |
68 | return QIcon(pixmaps.value(i: index.row()).scaled(w: m_PieceSize, h: m_PieceSize, |
69 | aspectMode: Qt::KeepAspectRatio, mode: Qt::SmoothTransformation)); |
70 | else if (role == Qt::UserRole) |
71 | return pixmaps.value(i: index.row()); |
72 | else if (role == Qt::UserRole + 1) |
73 | return locations.value(i: index.row()); |
74 | |
75 | return QVariant(); |
76 | } |
77 | |
78 | void PiecesModel::addPiece(const QPixmap &pixmap, const QPoint &location) |
79 | { |
80 | int row; |
81 | if (QRandomGenerator::global()->bounded(highest: 2) == 1) |
82 | row = 0; |
83 | else |
84 | row = pixmaps.size(); |
85 | |
86 | beginInsertRows(parent: QModelIndex(), first: row, last: row); |
87 | pixmaps.insert(i: row, t: pixmap); |
88 | locations.insert(i: row, t: location); |
89 | endInsertRows(); |
90 | } |
91 | |
92 | Qt::ItemFlags PiecesModel::flags(const QModelIndex &index) const |
93 | { |
94 | if (index.isValid()) |
95 | return (QAbstractListModel::flags(index)|Qt::ItemIsDragEnabled); |
96 | |
97 | return Qt::ItemIsDropEnabled; |
98 | } |
99 | |
100 | bool PiecesModel::removeRows(int row, int count, const QModelIndex &parent) |
101 | { |
102 | if (parent.isValid()) |
103 | return false; |
104 | |
105 | if (row >= pixmaps.size() || row + count <= 0) |
106 | return false; |
107 | |
108 | int beginRow = qMax(a: 0, b: row); |
109 | int endRow = qMin(a: row + count - 1, b: pixmaps.size() - 1); |
110 | |
111 | beginRemoveRows(parent, first: beginRow, last: endRow); |
112 | |
113 | while (beginRow <= endRow) { |
114 | pixmaps.removeAt(i: beginRow); |
115 | locations.removeAt(i: beginRow); |
116 | ++beginRow; |
117 | } |
118 | |
119 | endRemoveRows(); |
120 | return true; |
121 | } |
122 | |
123 | QStringList PiecesModel::mimeTypes() const |
124 | { |
125 | QStringList types; |
126 | types << "image/x-puzzle-piece" ; |
127 | return types; |
128 | } |
129 | |
130 | QMimeData *PiecesModel::mimeData(const QModelIndexList &indexes) const |
131 | { |
132 | QMimeData *mimeData = new QMimeData(); |
133 | QByteArray encodedData; |
134 | |
135 | QDataStream stream(&encodedData, QIODevice::WriteOnly); |
136 | |
137 | for (const QModelIndex &index : indexes) { |
138 | if (index.isValid()) { |
139 | QPixmap pixmap = qvariant_cast<QPixmap>(v: data(index, role: Qt::UserRole)); |
140 | QPoint location = data(index, role: Qt::UserRole+1).toPoint(); |
141 | stream << pixmap << location; |
142 | } |
143 | } |
144 | |
145 | mimeData->setData(mimetype: "image/x-puzzle-piece" , data: encodedData); |
146 | return mimeData; |
147 | } |
148 | |
149 | bool PiecesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, |
150 | int row, int column, const QModelIndex &parent) |
151 | { |
152 | if (!data->hasFormat(mimetype: "image/x-puzzle-piece" )) |
153 | return false; |
154 | |
155 | if (action == Qt::IgnoreAction) |
156 | return true; |
157 | |
158 | if (column > 0) |
159 | return false; |
160 | |
161 | int endRow; |
162 | |
163 | if (!parent.isValid()) { |
164 | if (row < 0) |
165 | endRow = pixmaps.size(); |
166 | else |
167 | endRow = qMin(a: row, b: pixmaps.size()); |
168 | } else { |
169 | endRow = parent.row(); |
170 | } |
171 | |
172 | QByteArray encodedData = data->data(mimetype: "image/x-puzzle-piece" ); |
173 | QDataStream stream(&encodedData, QIODevice::ReadOnly); |
174 | |
175 | while (!stream.atEnd()) { |
176 | QPixmap pixmap; |
177 | QPoint location; |
178 | stream >> pixmap >> location; |
179 | |
180 | beginInsertRows(parent: QModelIndex(), first: endRow, last: endRow); |
181 | pixmaps.insert(i: endRow, t: pixmap); |
182 | locations.insert(i: endRow, t: location); |
183 | endInsertRows(); |
184 | |
185 | ++endRow; |
186 | } |
187 | |
188 | return true; |
189 | } |
190 | |
191 | int PiecesModel::rowCount(const QModelIndex &parent) const |
192 | { |
193 | return parent.isValid() ? 0 : pixmaps.size(); |
194 | } |
195 | |
196 | Qt::DropActions PiecesModel::supportedDropActions() const |
197 | { |
198 | return Qt::CopyAction | Qt::MoveAction; |
199 | } |
200 | |
201 | void PiecesModel::addPieces(const QPixmap &pixmap) |
202 | { |
203 | if (!pixmaps.isEmpty()) { |
204 | beginRemoveRows(parent: QModelIndex(), first: 0, last: pixmaps.size() - 1); |
205 | pixmaps.clear(); |
206 | locations.clear(); |
207 | endRemoveRows(); |
208 | } |
209 | for (int y = 0; y < 5; ++y) { |
210 | for (int x = 0; x < 5; ++x) { |
211 | QPixmap pieceImage = pixmap.copy(ax: x*m_PieceSize, ay: y*m_PieceSize, awidth: m_PieceSize, aheight: m_PieceSize); |
212 | addPiece(pixmap: pieceImage, location: QPoint(x, y)); |
213 | } |
214 | } |
215 | } |
216 | |