Updated tests cases matching the new tabs
[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         Henri Lampela - henri.lampela@ixonos.com
7
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.
11
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.
16
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,
20     USA.
21 */
22
23
24 #include <QDebug>
25
26 #include "coordinates/scenecoordinate.h"
27 #include "friendgroupitem.h"
28 #include "friendlocationitem.h"
29 #include "mapcommon.h"
30 #include "mapscene.h"
31 #include "user/user.h"
32
33 #include "frienditemshandler.h"
34
35 FriendItemsHandler::FriendItemsHandler(MapScene *mapScene, QObject *parent)
36     : QObject(parent),
37       m_mapScene(mapScene),
38       m_zoomLevel(0)
39 {
40     qDebug() << __PRETTY_FUNCTION__;
41 }
42
43 void FriendItemsHandler::addFriendItem(User *friendData)
44 {
45     qDebug() << __PRETTY_FUNCTION__;
46
47     FriendLocationItem *item = new FriendLocationItem(friendData->userId());
48
49     item->setProfileImage(friendData->profileImage(), friendData->profileImageUrl());
50     item->setPos(SceneCoordinate(friendData->coordinates()).toPointF());
51     m_friendItems.append(item);
52     m_mapScene->addItem(item);
53
54     connect(item, SIGNAL(locationItemClicked(QList<QString>)),
55             this, SIGNAL(locationItemClicked(QList<QString>)));
56 }
57
58 void FriendItemsHandler::checkAllFriendsForCollidingFriends()
59 {
60     qDebug() << __PRETTY_FUNCTION__;
61
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);
67         }
68         iter++;
69     }
70 }
71
72 void FriendItemsHandler::checkFriendForCollidingFriends(FriendLocationItem *item)
73 {
74     // checkGroupsForCollisions() is used for checking if groups collide with another
75     // groups or friend items, so this method doesn't have to check against groups
76
77     qDebug() << __PRETTY_FUNCTION__;
78
79     FriendGroupItem *group = 0;
80
81     // loop through all friend items
82     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
83     while (iter != m_friendItems.end()) {
84         // but don't check myself and friends which are already part of a group
85         if (item != *iter && !(*iter)->isPartOfGroup()) {
86             if (collides(item, *iter)) {
87                 if (!group) {
88                     group = new FriendGroupItem(item);
89                     m_mapScene->addItem(group);
90                     m_friendGroupItems.append(group);
91
92                     connect(group, SIGNAL(locationItemClicked(QList<QString>)),
93                             this, SIGNAL(locationItemClicked(QList<QString>)));
94                 }
95                 group->joinFriend(*iter);
96             }
97         }
98         iter++;
99     }
100 }
101
102 bool FriendItemsHandler::collides(BaseLocationItem *item1, BaseLocationItem *item2)
103 {
104     QRect item1Rect = item1->sceneTransformedBoundingRect(m_zoomLevel);
105     QRect item2Rect = item2->sceneTransformedBoundingRect(m_zoomLevel);
106
107     if (item1Rect.intersects(item2Rect))
108         return true;
109
110     if (item1Rect.left() < (OSM_MAP_MIN_PIXEL_X + item1Rect.width() / 2)) {
111         QRect translated = item1Rect.translated(OSM_MAP_PIXELS_X, 0);
112         if (translated.intersects(item2Rect))
113             return true;
114     } else if (item1Rect.right() > (OSM_MAP_MAX_PIXEL_X  - item1Rect.width() / 2)) {
115         QRect translated = item1Rect.translated(-OSM_MAP_PIXELS_X, 0);
116         if (translated.intersects(item2Rect))
117             return true;
118     }
119
120     return false;
121 }
122
123 void FriendItemsHandler::deleteFriendItem(FriendLocationItem *item)
124 {
125     qDebug() << __PRETTY_FUNCTION__;
126
127     m_mapScene->removeItem(item);
128     delete item;
129 }
130
131 void FriendItemsHandler::destructGroups()
132 {
133     foreach (FriendGroupItem *group, m_friendGroupItems)
134         group->dropFriends();
135
136     qDeleteAll(m_friendGroupItems);
137     m_friendGroupItems.clear();
138 }
139
140 void FriendItemsHandler::friendImageReady(User *user)
141 {
142    qDebug() << __PRETTY_FUNCTION__;
143
144    foreach (FriendLocationItem *friendItem, m_friendItems) {
145        if (user->userId() == friendItem->userId()) {
146            friendItem->setProfileImage(user->profileImage(), user->profileImageUrl());
147            break;
148        }
149    }
150 }
151
152 void FriendItemsHandler::friendListUpdated(QList<User *> &friendsList)
153 {
154     qDebug() << __PRETTY_FUNCTION__;
155
156     destructGroups();
157
158     // loop through friend items and find matching friend data. If matching data
159     // is not found then remove item
160     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
161     while (iter != m_friendItems.end()) {
162         bool found = false;
163         foreach (User * friendData, friendsList) {
164             if (friendData->userId() == (*iter)->userId()) {
165                 found = true;
166                 break;
167             }
168         }
169         if (!found) {
170             // data for friend item was not found so item must be deleted
171             deleteFriendItem(*iter);
172             iter = m_friendItems.erase(iter);
173         }
174         else {
175             iter++;
176         }
177     }
178
179     // loop through new friend data, find matching friend items and update them, or add new items
180     // if old items are not found
181     foreach (User * friendData, friendsList) {
182         bool found = false;
183         foreach (FriendLocationItem *friendItem, m_friendItems) {
184             if (friendData->userId() == friendItem->userId()) {
185                 // friend item was found so update the data
186                 updateFriendItem(friendItem, friendData);
187                 found = true;
188                 break;
189             }
190         }
191         if (!found) {
192             // friend item was not found so new item must be added
193             addFriendItem(friendData);
194         }
195     }
196
197     checkAllFriendsForCollidingFriends();
198 }
199
200 void FriendItemsHandler::refactorFriendItems(int zoomLevel)
201 {
202     qDebug() << __PRETTY_FUNCTION__;
203
204     m_zoomLevel = zoomLevel;
205
206     destructGroups();
207     checkAllFriendsForCollidingFriends();
208 }
209
210 void FriendItemsHandler::updateFriendItem(FriendLocationItem *friendItem, User *friendData)
211 {
212     qDebug() << __PRETTY_FUNCTION__;
213
214     // update position
215     friendItem->setPos(SceneCoordinate(friendData->coordinates()).toPointF());
216
217     // update image
218     if (friendItem->profileImageUrl() != friendData->profileImageUrl())
219         friendItem->setProfileImage(friendData->profileImage(), friendData->profileImageUrl());
220 }