1 /*
2 Drawpile - a collaborative drawing program.
3
4 Copyright (C) 2015-2018 Calle Laakkonen
5
6 Drawpile is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Drawpile is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Drawpile. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "usercursormodel.h"
21 #include "layerlist.h"
22
23 #include <QDateTime>
24 #include <QTimerEvent>
25 #include <QDebug>
26
27 namespace canvas {
28
29 // Hide cursors after they have not moved for this many milliseconds
30 static const qint64 AUTOHIDE_TIME = 3000;
31
UserCursorModel(QObject * parent)32 UserCursorModel::UserCursorModel(QObject *parent)
33 : QAbstractListModel(parent), m_layerlist(nullptr)
34 {
35 m_timerId = startTimer(1000, Qt::VeryCoarseTimer);
36 }
37
rowCount(const QModelIndex & parent) const38 int UserCursorModel::rowCount(const QModelIndex &parent) const
39 {
40 if(parent.isValid())
41 return 0;
42 return m_cursors.size();
43 }
44
indexForId(int id) const45 QModelIndex UserCursorModel::indexForId(int id) const
46 {
47 for(int i=0;i<m_cursors.size();++i)
48 if(m_cursors.at(i).id == id)
49 return index(i);
50 return QModelIndex();
51 }
52
data(const QModelIndex & index,int role) const53 QVariant UserCursorModel::data(const QModelIndex &index, int role) const
54 {
55 if(index.isValid() && index.row() >= 0 && index.row() < m_cursors.size()) {
56 const UserCursor &uc = m_cursors.at(index.row());
57 switch(role) {
58 case Qt::DisplayRole: return uc.name;
59 case Qt::DecorationRole: return uc.avatar;
60 case IdRole: return uc.id;
61 case PositionRole: return uc.pos;
62 case LayerRole: return uc.layer;
63 case ColorRole: return uc.color;
64 case VisibleRole: return uc.visible;
65 default: break;
66 }
67 }
68 return QVariant();
69 }
70
roleNames() const71 QHash<int, QByteArray> UserCursorModel::roleNames() const
72 {
73 QHash<int, QByteArray> roles;
74 roles[Qt::DisplayRole] = "display";
75 roles[Qt::DecorationRole] = "decoration";
76 roles[IdRole] = "id";
77 roles[PositionRole] = "pos";
78 roles[LayerRole] = "layer";
79 roles[ColorRole] = "color";
80 roles[VisibleRole] = "visible";
81 return roles;
82 }
83
84
setCursorName(int id,const QString & name)85 void UserCursorModel::setCursorName(int id, const QString &name)
86 {
87 QModelIndex index;
88 UserCursor *uc = getOrCreate(id, index);
89
90 uc->name = name;
91
92 emit dataChanged(index, index, QVector<int>() << Qt::DisplayRole);
93 }
94
setCursorAvatar(int id,const QPixmap & avatar)95 void UserCursorModel::setCursorAvatar(int id, const QPixmap &avatar)
96 {
97 QModelIndex index;
98 UserCursor *uc = getOrCreate(id, index);
99
100 uc->avatar = avatar;
101
102 emit dataChanged(index, index, QVector<int>() << Qt::DecorationRole);
103 }
104
setCursorColor(int id,const QColor & color)105 void UserCursorModel::setCursorColor(int id, const QColor &color)
106 {
107 QModelIndex index;
108 UserCursor *uc = getOrCreate(id, index);
109
110 uc->color = color;
111
112 emit dataChanged(index, index, QVector<int>() << ColorRole);
113 }
114
setCursorPosition(int id,int layerId,const QPoint & pos)115 void UserCursorModel::setCursorPosition(int id, int layerId, const QPoint &pos)
116 {
117 QModelIndex index;
118 UserCursor *uc = getOrCreate(id, index);
119
120 QVector<int> roles;
121
122 uc->pos = pos; roles << PositionRole;
123 uc->lastMoved = QDateTime::currentMSecsSinceEpoch();
124 if(!uc->visible) {
125 uc->visible = true;
126 roles << VisibleRole;
127 }
128
129 if(layerId>0 && layerId != uc->layerId) {
130 uc->layerId = layerId;
131 QString layerName = QStringLiteral("???");
132 if(m_layerlist) {
133 QVariant ln = m_layerlist->layerIndex(layerId).data(LayerListModel::TitleRole);
134 if(!ln.isNull())
135 layerName = ln.toString();
136 }
137 uc->layer = layerName;
138 roles << LayerRole;
139 }
140
141 emit dataChanged(index, index, roles);
142 }
143
hideCursor(int id)144 void UserCursorModel::hideCursor(int id)
145 {
146 for(int i=0;i<m_cursors.size();++i) {
147 if(m_cursors.at(i).id == id) {
148 // Leave the cursor visible for just a little while longer
149 // This makes it easier to catch who drew something and gives
150 // the navigator time to render the marker
151 m_cursors[i].lastMoved = QDateTime::currentMSecsSinceEpoch() - AUTOHIDE_TIME + 1000;
152
153 QModelIndex idx = index(i);
154 emit dataChanged(idx, idx, QVector<int>() << VisibleRole);
155 return;
156 }
157 }
158 }
159
removeCursor(int id)160 void UserCursorModel::removeCursor(int id)
161 {
162 for(int i=0;i<m_cursors.size();++i) {
163 if(m_cursors.at(i).id == id) {
164 beginRemoveRows(QModelIndex(), i, i);
165 m_cursors.remove(i);
166 endRemoveRows();
167 return;
168 }
169 }
170 }
171
clear()172 void UserCursorModel::clear()
173 {
174 beginResetModel();
175 m_cursors.clear();
176 endResetModel();
177 }
178
getOrCreate(int id,QModelIndex & idx)179 UserCursor *UserCursorModel::getOrCreate(int id, QModelIndex &idx)
180 {
181 for(int i=0;i<m_cursors.size();++i) {
182 if(m_cursors.at(i).id == id) {
183 idx = index(i);
184 return &m_cursors[i];
185 }
186 }
187
188 beginInsertRows(QModelIndex(), m_cursors.size(), m_cursors.size());
189 m_cursors.append(UserCursor {
190 id,
191 false,
192 QDateTime::currentMSecsSinceEpoch(),
193 0,
194 QPoint(),
195 QStringLiteral("#%1").arg(id),
196 QString(),
197 QColor(Qt::black),
198 QPixmap()
199 });
200 endInsertRows();
201
202 idx = index(m_cursors.size()-1);
203 return &m_cursors[m_cursors.size()-1];
204 }
205
timerEvent(QTimerEvent * e)206 void UserCursorModel::timerEvent(QTimerEvent *e)
207 {
208 if(e->timerId() != m_timerId) {
209 QAbstractListModel::timerEvent(e);
210 return;
211 }
212
213 const qint64 now = QDateTime::currentMSecsSinceEpoch();
214 const qint64 hideTreshold = now - AUTOHIDE_TIME;
215
216 for(int i=0;i<m_cursors.size();++i) {
217 UserCursor &uc = m_cursors[i];
218
219 if(uc.visible && uc.lastMoved < hideTreshold) {
220 uc.visible = false;
221 QModelIndex idx = index(i);
222 emit dataChanged(idx, idx, QVector<int>() << VisibleRole);
223 }
224 }
225 }
226
227 }
228