1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 2007-2011 Licq developers
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "contactgroup.h"
21 
22 #include <licq/contactlist/group.h>
23 #include <licq/contactlist/usermanager.h>
24 
25 #include "contactbar.h"
26 #include "contactlist.h"
27 #include "contactuser.h"
28 
29 using namespace LicqQtGui;
30 
ContactGroup(int id,const QString & name,unsigned showMask,unsigned hideMask)31 ContactGroup::ContactGroup(int id, const QString& name, unsigned showMask, unsigned hideMask)
32   : ContactItem(ContactListModel::GroupItem),
33     myGroupId(id),
34     myName(name),
35     myEvents(0),
36     myVisibleContacts(0),
37     myShowMask(showMask),
38     myHideMask(hideMask)
39 {
40   // Put "Other Users" last when sorting
41   if (myGroupId == ContactListModel::OtherUsersGroupId)
42     mySortKey = 65535;
43   else
44     mySortKey = myGroupId;
45 
46   update();
47 
48   for (int i = 0; i < 3; ++i)
49     myBars[i] = new ContactBar(static_cast<ContactListModel::SubGroupType>(i), this);
50 }
51 
ContactGroup(const Licq::Group * group)52 ContactGroup::ContactGroup(const Licq::Group* group)
53   : ContactItem(ContactListModel::GroupItem),
54     myGroupId(group->id()),
55     myName(QString::fromLocal8Bit(group->name().c_str())),
56     mySortKey(group->sortIndex()),
57     myEvents(0),
58     myVisibleContacts(0),
59     myShowMask(0),
60     myHideMask(ContactListModel::IgnoreStatus)
61 {
62   for (int i = 0; i < 3; ++i)
63     myBars[i] = new ContactBar(static_cast<ContactListModel::SubGroupType>(i), this);
64 }
65 
~ContactGroup()66 ContactGroup::~ContactGroup()
67 {
68   // Remove all user instances in this group
69   while (!myUsers.isEmpty())
70     delete myUsers.takeFirst();
71 
72   for (int i = 0; i < 3; ++i)
73     delete myBars[i];
74 }
75 
update()76 void ContactGroup::update()
77 {
78   // System groups and "Other users" aren't present in daemon group list
79   if (myGroupId == ContactListModel::OtherUsersGroupId ||
80       myGroupId >= ContactListModel::SystemGroupOffset)
81     return;
82 
83   {
84     Licq::GroupReadGuard g(myGroupId);
85     if (!g.isLocked())
86       return;
87 
88     myName = QString::fromLocal8Bit(g->name().c_str());
89     mySortKey = g->sortIndex();
90   }
91 
92   emit dataChanged(this);
93 }
94 
updateSortKey()95 void ContactGroup::updateSortKey()
96 {
97   // System groups and "Other users" aren't present in daemon group list
98   if (myGroupId == ContactListModel::OtherUsersGroupId ||
99       myGroupId >= ContactListModel::SystemGroupOffset)
100     return;
101 
102   Licq::GroupReadGuard g(myGroupId);
103   if (!g.isLocked())
104     return;
105 
106   mySortKey = g->sortIndex();
107 }
108 
item(int row) const109 ContactItem* ContactGroup::item(int row) const
110 {
111   if (row < 3)
112     return myBars[row];
113   else
114     return myUsers.value(row - 3);
115 }
116 
user(ContactUserData * u) const117 ContactUser* ContactGroup::user(ContactUserData* u) const
118 {
119   foreach (ContactUser* instance, myUsers)
120   {
121     if (instance->userData() == u)
122       return instance;
123   }
124 
125   return 0;
126 }
127 
rowCount() const128 int ContactGroup::rowCount() const
129 {
130   // Add the separator bars
131   return myUsers.size() + 3;
132 }
133 
indexOf(ContactUser * user) const134 int ContactGroup::indexOf(ContactUser* user) const
135 {
136   // The separator bars come first so add three to the index
137   return myUsers.indexOf(user) + 3;
138 }
139 
addUser(ContactUser * user,ContactListModel::SubGroupType subGroup)140 void ContactGroup::addUser(ContactUser* user, ContactListModel::SubGroupType subGroup)
141 {
142   // Insert user in model
143   emit beginInsert(this, rowCount());
144   myUsers.append(user);
145   emit endInsert();
146 
147   // Update group data
148   myEvents += user->numEvents();
149   if (user->visibility())
150     myVisibleContacts++;
151   emit dataChanged(this);
152 
153   // Update bar data
154   myBars[subGroup]->countIncrease();
155   myBars[subGroup]->updateNumEvents(user->numEvents());
156   if (user->visibility())
157     myBars[subGroup]->updateVisibility(true);
158   emit barDataChanged(myBars[subGroup], subGroup);
159 }
160 
removeUser(ContactUser * user,ContactListModel::SubGroupType subGroup)161 void ContactGroup::removeUser(ContactUser* user, ContactListModel::SubGroupType subGroup)
162 {
163   // Update bar data
164   myBars[subGroup]->countDecrease();
165   myBars[subGroup]->updateNumEvents(-user->numEvents());
166   if (user->visibility())
167     myBars[subGroup]->updateVisibility(false);
168   emit barDataChanged(myBars[subGroup], subGroup);
169 
170   // Remove user from model
171   emit beginRemove(this, indexOf(user));
172   myUsers.removeAll(user);
173   emit endRemove();
174 
175   // Update group data
176   myEvents -= user->numEvents();
177   if (user->visibility())
178     myVisibleContacts--;
179   emit dataChanged(this);
180 }
181 
acceptUser(unsigned extendedStatus)182 bool ContactGroup::acceptUser(unsigned extendedStatus)
183 {
184   // User must not match any bits in the hide mask
185   if (myHideMask != 0 && (extendedStatus & myHideMask))
186     return false;
187 
188   // User must match at least one bit in the show mask
189   if (myShowMask != 0 && !(extendedStatus & myShowMask))
190     return false;
191 
192   // Default, accept user
193   return true;
194 }
195 
updateSubGroup(ContactListModel::SubGroupType oldSubGroup,ContactListModel::SubGroupType newSubGroup,int eventCounter)196 void ContactGroup::updateSubGroup(ContactListModel::SubGroupType oldSubGroup, ContactListModel::SubGroupType newSubGroup, int eventCounter)
197 {
198   myBars[oldSubGroup]->countDecrease();
199   myBars[oldSubGroup]->updateNumEvents(-eventCounter);
200   emit barDataChanged(myBars[oldSubGroup], oldSubGroup);
201 
202   myBars[newSubGroup]->countIncrease();
203   myBars[newSubGroup]->updateNumEvents(eventCounter);
204   emit barDataChanged(myBars[newSubGroup], newSubGroup);
205 }
206 
updateNumEvents(int counter,ContactListModel::SubGroupType subGroup)207 void ContactGroup::updateNumEvents(int counter, ContactListModel::SubGroupType subGroup)
208 {
209   if (counter == 0)
210     return;
211 
212   // Update bar data
213   myBars[subGroup]->updateNumEvents(counter);
214   emit barDataChanged(myBars[subGroup], subGroup);
215 
216   // Update group data
217   myEvents += counter;
218   emit dataChanged(this);
219 }
220 
updateVisibility(bool increase,ContactListModel::SubGroupType subGroup)221 void ContactGroup::updateVisibility(bool increase, ContactListModel::SubGroupType subGroup)
222 {
223   // Update bar data
224   myBars[subGroup]->updateVisibility(increase);
225   emit barDataChanged(myBars[subGroup], subGroup);
226 
227   // Update group data
228   if (increase)
229     myVisibleContacts++;
230   else
231     myVisibleContacts--;
232   emit dataChanged(this);
233 }
234 
data(int column,int role) const235 QVariant ContactGroup::data(int column, int role) const
236 {
237   switch (role)
238   {
239     case Qt::DisplayRole:
240       if (column == 0)
241       {
242         int onlineCount = myBars[ContactListModel::OnlineSubGroup]->count();
243         if (onlineCount > 0)
244           return myName + " (" + QString::number(onlineCount) + ")";
245         else
246           return myName;
247       }
248       break;
249 
250     case ContactListModel::NameRole:
251       return myName;
252 
253     case ContactListModel::ItemTypeRole:
254       return ContactListModel::GroupItem;
255 
256     case ContactListModel::SortPrefixRole:
257       return 0;
258 
259     case ContactListModel::SortRole:
260       return mySortKey;
261 
262     case ContactListModel::UnreadEventsRole:
263       return myEvents;
264 
265     case ContactListModel::GroupIdRole:
266       return myGroupId;
267 
268     case ContactListModel::UserCountRole:
269       return myUsers.size();
270 
271     case ContactListModel::VisibilityRole:
272       return (myVisibleContacts > 0);
273   }
274 
275   return QVariant();
276 }
277 
setData(const QVariant & value,int role)278 bool ContactGroup::setData(const QVariant& value, int role)
279 {
280   if (role != ContactListModel::NameRole || !value.isValid())
281     return false;
282 
283   // Don't allow system groups or "Other users" to be renamed this way
284   if (myGroupId == ContactListModel::OtherUsersGroupId ||
285       myGroupId >= ContactListModel::SystemGroupOffset)
286     return false;
287 
288   QString newName = value.toString();
289   if (newName == myName)
290     return true;
291 
292   // Don't save new name here, daemon will signal us when name has changed
293   Licq::gUserManager.RenameGroup(myGroupId, newName.toLocal8Bit().constData());
294 
295   return true;
296 }
297