2 Situare - A location system for Facebook
3 Copyright (C) 2010 Ixonos Plc. Authors:
5 Sami Rämö - sami.ramo@ixonos.com
6 Henri Lampela - henri.lampela@ixonos.com
8 Situare is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 version 2 as published by the Free Software Foundation.
12 Situare is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Situare; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
26 #include "friendgroupitem.h"
27 #include "friendlocationitem.h"
28 #include "mapcommon.h"
29 #include "mapengine.h"
31 #include "user/user.h"
33 #include "frienditemshandler.h"
35 FriendItemsHandler::FriendItemsHandler(MapScene *mapScene, QObject *parent)
40 qDebug() << __PRETTY_FUNCTION__;
43 void FriendItemsHandler::addFriendItem(User *friendData)
45 qDebug() << __PRETTY_FUNCTION__;
47 FriendLocationItem *item = new FriendLocationItem(friendData->userId());
49 item->setProfileImage(friendData->profileImage(), friendData->profileImageUrl());
50 item->setPos(MapEngine::convertLatLonToSceneCoordinate(friendData->coordinates()));
51 m_friendItems.append(item);
52 m_mapScene->addItem(item);
54 connect(item, SIGNAL(locationItemClicked(QList<QString>)),
55 this, SIGNAL(locationItemClicked(QList<QString>)));
58 void FriendItemsHandler::checkAllFriendsForCollidingFriends()
60 qDebug() << __PRETTY_FUNCTION__;
62 QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
63 while (iter != m_friendItems.end()) {
64 // check only friends which are not part of group already
65 if (!(*iter)->isPartOfGroup()) {
66 checkFriendForCollidingFriends(*iter);
72 void FriendItemsHandler::checkAllGroupsForCollidingFriends()
74 qDebug() << __PRETTY_FUNCTION__;
76 // loop through all groups
77 QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
78 while (iter != m_friendGroupItems.end()) {
79 checkGroupForCollidingFriends(*iter);
84 void FriendItemsHandler::checkFriendForCollidingFriends(FriendLocationItem *item)
86 // checkGroupsForCollisions() is used for checking if groups collide with another
87 // groups or friend items, so this method doesn't have to check against groups
89 qDebug() << __PRETTY_FUNCTION__;
91 FriendGroupItem *group = 0;
93 // loop through all friend items
94 QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
95 while (iter != m_friendItems.end()) {
96 // but don't check myself and friends which are already part of a group
97 if (item != *iter && !(*iter)->isPartOfGroup()) {
98 if (collides(item, *iter)) {
100 group = new FriendGroupItem(item);
101 m_mapScene->addItem(group);
102 m_friendGroupItems.append(group);
104 connect(group, SIGNAL(locationItemClicked(QList<QString>)),
105 this, SIGNAL(locationItemClicked(QList<QString>)));
107 group->joinFriend(*iter);
114 void FriendItemsHandler::checkGroupForCollidingFriends(FriendGroupItem *group)
116 qDebug() << __PRETTY_FUNCTION__;
118 // loop through all friend items
119 QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
120 while (iter != m_friendItems.end()) {
121 // but don't check friends which are already part of a group
122 if (!(*iter)->isPartOfGroup()) {
123 if (collides(group, *iter)) {
124 group->joinFriend(*iter);
131 void FriendItemsHandler::checkGroupForCollidingGroups(FriendGroupItem *group)
133 qDebug() << __PRETTY_FUNCTION__;
135 // loop through all groups
136 QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
137 while (iter != m_friendGroupItems.end()) {
138 // but don't check myself
139 if (group != *iter) {
140 if (collides(group, *iter)) {
141 (*iter)->mergeWithGroup(group);
142 m_mapScene->removeItem(*iter);
144 iter = m_friendGroupItems.erase(iter);
156 bool FriendItemsHandler::collides(BaseLocationItem *item1, BaseLocationItem *item2)
158 QRect rect = item1->sceneTransformedBoundingRect(m_zoomLevel);
160 if (rect.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
163 if (rect.left() < MAP_MIN_PIXEL_X) {
164 QRect translated = rect.translated(MAP_PIXELS_X, 0);
165 if (translated.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
169 if (rect.right() > MAP_MAX_PIXEL_X) {
170 QRect translated = rect.translated(-MAP_PIXELS_X, 0);
171 if (translated.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
178 void FriendItemsHandler::deleteFriendItem(FriendLocationItem *item)
180 qDebug() << __PRETTY_FUNCTION__;
182 dropFriendFromAllGroups(item);
183 m_mapScene->removeItem(item);
187 void FriendItemsHandler::dropFriendFromAllGroups(FriendLocationItem *item)
189 qDebug() << __PRETTY_FUNCTION__;
191 foreach (FriendGroupItem *group, m_friendGroupItems) {
192 group->dropFriend(item);
196 void FriendItemsHandler::dropOutOfGroupFriends()
198 qDebug() << __PRETTY_FUNCTION__;
200 // loop through all group items and drop friends which doesn't collide anymore
201 // delete group if possible
202 foreach (FriendGroupItem *group, m_friendGroupItems) {
203 if (group->dropFriends(m_zoomLevel)) {
204 m_friendGroupItems.removeAll(group);
205 m_mapScene->removeItem(group);
211 void FriendItemsHandler::friendImageReady(User *user)
213 qDebug() << __PRETTY_FUNCTION__;
215 foreach (FriendLocationItem *friendItem, m_friendItems) {
216 if (user->userId() == friendItem->userId()) {
217 friendItem->setProfileImage(user->profileImage(), user->profileImageUrl());
223 void FriendItemsHandler::friendListUpdated(QList<User *> &friendsList)
225 qDebug() << __PRETTY_FUNCTION__;
227 // loop through friend items and find matching friend data. If matching data
228 // is not found then remove item
229 QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
230 while (iter != m_friendItems.end()) {
232 foreach (User * friendData, friendsList) {
233 if (friendData->userId() == (*iter)->userId()) {
239 // data for friend item was not found so item must be deleted
240 deleteFriendItem(*iter);
241 iter = m_friendItems.erase(iter);
248 // loop through new friend data, find matching friend items and update them, or add new items
249 // if old items are not found
250 foreach (User * friendData, friendsList) {
252 foreach (FriendLocationItem *friendItem, m_friendItems) {
253 if (friendData->userId() == friendItem->userId()) {
254 // friend item was found so update the data
255 updateFriendItem(friendItem, friendData);
261 // friend item was not found so new item must be added
262 addFriendItem(friendData);
266 refactorFriendItems(m_zoomLevel);
269 void FriendItemsHandler::mergeCollidingGroups()
271 qDebug() << __PRETTY_FUNCTION__;
273 // loop through all groups
274 QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
275 while (iter != m_friendGroupItems.end()) {
276 checkGroupForCollidingGroups(*iter);
281 void FriendItemsHandler::refactorFriendItems(int zoomLevel)
283 qDebug() << __PRETTY_FUNCTION__;
285 m_zoomLevel = zoomLevel;
287 for (int repeat = 2; repeat > 0; repeat--) {
288 mergeCollidingGroups();
289 dropOutOfGroupFriends();
290 checkAllGroupsForCollidingFriends();
291 checkAllFriendsForCollidingFriends();
295 void FriendItemsHandler::updateFriendItem(FriendLocationItem *friendItem, User *friendData)
297 qDebug() << __PRETTY_FUNCTION__;
300 QPoint newPosition = MapEngine::convertLatLonToSceneCoordinate(friendData->coordinates());
301 if (friendItem->pos().toPoint() != newPosition)
302 friendItem->setPos(newPosition);
305 if (friendItem->profileImageUrl() != friendData->profileImageUrl())
306 friendItem->setProfileImage(friendData->profileImage(), friendData->profileImageUrl());