Fixed defects found in review
[situare] / src / map / frienditemshandler.cpp
1 /*
2     Situare - A location system for Facebook
3     Copyright (C) 2010  Ixonos Plc. Authors:
4
5         Sami Rämö - sami.ramo@ixonos.com
6
7     Situare is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     version 2 as published by the Free Software Foundation.
10
11     Situare 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 Situare; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
19     USA.
20 */
21
22
23 #include <QDebug>
24
25 #include "friendgroupitem.h"
26 #include "friendlocationitem.h"
27 #include "mapengine.h"
28 #include "mapscene.h"
29 #include "user/user.h"
30
31 #include "frienditemshandler.h"
32
33 FriendItemsHandler::FriendItemsHandler(MapScene *mapScene, QObject *parent)
34     : QObject(parent),
35       m_mapScene(mapScene),
36       m_zoomLevel(0)
37 {
38     qDebug() << __PRETTY_FUNCTION__;
39 }
40
41 void FriendItemsHandler::checkAllFriendsForCollidingFriends()
42 {
43     qDebug() << __PRETTY_FUNCTION__;
44
45     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
46     while (iter != m_friendItems.end()) {
47         // check only friends which are not part of group already
48         if (!(*iter)->isPartOfGroup()) {
49             checkFriendForCollidingFriends(*iter);
50         }
51         iter++;
52     }
53 }
54
55 void FriendItemsHandler::checkAllGroupsForCollidingFriends()
56 {
57     qDebug() << __PRETTY_FUNCTION__;
58
59     // loop through all groups
60     QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
61     while (iter != m_friendGroupItems.end()) {
62         checkGroupForCollidingFriends(*iter);
63         iter++;
64     }
65 }
66
67 void FriendItemsHandler::checkFriendForCollidingFriends(FriendLocationItem *item)
68 {
69     // checkGroupsForCollisions() is used for checking if groups collide with another
70     // groups or friend items, so this method doesn't have to check against groups
71
72     qDebug() << __PRETTY_FUNCTION__;
73
74     FriendGroupItem *group = 0;
75     QRect itemSceneRect = item->sceneTransformedBoundingRect(m_zoomLevel);
76
77     // loop through all friend items
78     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
79     while (iter != m_friendItems.end()) {
80         // but don't check myself and friends which are already part of a group
81         if (item != *iter && !(*iter)->isPartOfGroup()) {
82             if (itemSceneRect.intersects((*iter)->sceneTransformedBoundingRect(m_zoomLevel))) {
83                 if (!group) {
84                     group = new FriendGroupItem(item);
85                     m_mapScene->addItem(group);
86                     m_friendGroupItems.append(group);
87                 }
88                 group->joinFriend(*iter);
89             }
90         }
91         iter++;
92     }
93 }
94
95 void FriendItemsHandler::checkGroupForCollidingFriends(FriendGroupItem *group)
96 {
97     qDebug() << __PRETTY_FUNCTION__;
98
99     QRect groupSceneRect = group->sceneTransformedBoundingRect(m_zoomLevel);
100
101     // loop through all friend items
102     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
103     while (iter != m_friendItems.end()) {
104         // but don't check friends which are already part of a group
105         if (!(*iter)->isPartOfGroup()) {
106             if (groupSceneRect.intersects((*iter)->sceneTransformedBoundingRect(m_zoomLevel))) {
107                 group->joinFriend(*iter);
108             }
109         }
110         iter++;
111     }
112 }
113
114 void FriendItemsHandler::checkGroupForCollidingGroups(FriendGroupItem *group)
115 {
116     qDebug() << __PRETTY_FUNCTION__;
117
118     QRect groupSceneRect = group->sceneTransformedBoundingRect(m_zoomLevel);
119
120     // loop through all groups
121     QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
122     while (iter != m_friendGroupItems.end()) {
123         // but don't check myself
124         if (group != *iter) {
125             if (groupSceneRect.intersects((*iter)->sceneTransformedBoundingRect(m_zoomLevel))) {
126                 (*iter)->mergeWithGroup(group);
127                 m_mapScene->removeItem(*iter);
128                 delete *iter;
129                 iter = m_friendGroupItems.erase(iter);
130             }
131             else {
132                 iter++;
133             }
134         }
135         else {
136             iter++;
137         }
138     }
139 }
140
141 void FriendItemsHandler::mergeCollidingGroups()
142 {
143     qDebug() << __PRETTY_FUNCTION__;
144
145     // loop through all groups
146     QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
147     while (iter != m_friendGroupItems.end()) {
148         checkGroupForCollidingGroups(*iter);
149         iter++;
150     }
151 }
152
153 void FriendItemsHandler::cleanOldFriendData(const QList<User *> &friendsList)
154 {
155     qDebug() << __PRETTY_FUNCTION__;
156
157     // loop through all m_friendItem items
158     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
159     while (iter != m_friendItems.end()) {
160         bool friendFound = false;
161
162         // check against each item in the friendsList
163         QList<User *>::const_iterator j;
164         for (j = friendsList.begin(); j != friendsList.end(); j++) {
165             if ((**iter).userId() == (**j).userId()) {
166                 friendFound = true;
167                 break;
168             }
169         }
170
171         if (!friendFound) {
172             m_mapScene->removeItem(*iter);
173             delete *iter;
174             iter = m_friendItems.erase(iter);
175         }
176         else {
177             iter++;
178         }
179     }
180 }
181
182 void FriendItemsHandler::dropOutOfGroupFriends()
183 {
184     qDebug() << __PRETTY_FUNCTION__;
185
186     // loop through all group items and drop friends which doesn't collide anymore
187     // delete group if possible
188     foreach (FriendGroupItem *group, m_friendGroupItems) {
189         if (group->dropFriends(m_zoomLevel)) {
190             m_friendGroupItems.removeAll(group);
191             m_mapScene->removeItem(group);
192             delete group;
193         }
194     }
195 }
196
197 void FriendItemsHandler::receiveFriendLocations(QList<User *> &friendsList)
198 {
199     qDebug() << __PRETTY_FUNCTION__;
200
201     static int receiveFriendsLocationsCounter = 0;
202
203     if (receiveFriendsLocationsCounter == 0) {
204         receiveFriendsLocationsCounter++;
205         updateFriendItemList(friendsList);
206     }
207
208     else {
209         /// @todo VILLE: New friends are never added to list & scene
210         receiveFriendsLocationsCounter++;
211         updateFriendLocationsAndImages(friendsList);
212         cleanOldFriendData(friendsList);
213     }
214
215     refactorFriendItems(m_zoomLevel);
216 }
217
218 void FriendItemsHandler::refactorFriendItems(int zoomLevel)
219 {
220     qDebug() << __PRETTY_FUNCTION__;
221
222     m_zoomLevel = zoomLevel;
223
224     mergeCollidingGroups();
225     dropOutOfGroupFriends();
226     checkAllGroupsForCollidingFriends();
227     checkAllFriendsForCollidingFriends();
228 }
229
230 void FriendItemsHandler::updateFriendItemList(const QList<User *> &friendsList)
231 {
232     qDebug() << __PRETTY_FUNCTION__;
233
234     qDeleteAll(m_friendItems.begin(),m_friendItems.end());
235     m_friendItems.clear();
236
237
238     for (int i=0; i<friendsList.count(); i++) {
239         FriendLocationItem *friendLocation
240                 = new FriendLocationItem(friendsList.at(i)->profileImage(),
241                                          friendsList.at(i)->coordinates(),0);
242
243         friendLocation->setUserId(friendsList.at(i)->userId());
244         m_friendItems.append(friendLocation);
245         m_mapScene->addItem(friendLocation);
246
247         refactorFriendItems(m_zoomLevel);
248     }
249 }
250
251 void FriendItemsHandler::updateFriendLocationsAndImages(const QList<User *> &friendsList)
252 {
253     qDebug() << __PRETTY_FUNCTION__;
254
255     for (int i=0; i<friendsList.count(); i++) {
256
257         QLinkedList<FriendLocationItem *>::iterator iter;
258         for (iter = m_friendItems.begin(); iter!= m_friendItems.end(); iter++) {
259
260             if ((*iter)->userId() == friendsList.at(i)->userId()) {
261
262                 if ((*iter)->position()
263                     != MapEngine::convertLatLonToSceneCoordinate(friendsList.at(i)->coordinates()))
264                     (*iter)->setPosition(friendsList.at(i)->coordinates());
265
266                 if ((*iter)->profileImageUrl()
267                     != friendsList.at(i)->profileImageUrl()) {
268                     (*iter)->setPixmap(friendsList.at(i)->profileImage());
269                     (*iter)->setProfileImageUrl(friendsList.at(i)->profileImageUrl());
270                 }
271             }
272         }
273     }
274 }