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 #ifndef CONTACTLISTMODEL_H 21 #define CONTACTLISTMODEL_H 22 23 #include <QAbstractItemModel> 24 #include <QList> 25 26 #include <licq/userid.h> 27 28 namespace Licq 29 { 30 class User; 31 } 32 33 // Allow UserId to be used in QVariant and QSet 34 Q_DECLARE_METATYPE(Licq::UserId) 35 uint qHash(const Licq::UserId& userId); 36 37 namespace LicqQtGui 38 { 39 // Internal data classes for ContactList 40 class ContactUserData; 41 class ContactUser; 42 class ContactBar; 43 class ContactGroup; 44 45 /** 46 * A QT-model representation of the licq contact list 47 * 48 * The contact list is presented as a two level tree structure with the groups 49 * as top level items and contacts located in the groups. 50 * Each group also contains separator bars as items together with the contacts. 51 * Special groups like "Invisible", "Online Notify" and "All Users" are present 52 * as normal groups but with special group IDs. 53 * 54 * Before this model can be used by a view a proxy model is needed to sort the 55 * list and to hide the special groups, ignored contacts and offline contacts 56 * depending on the view mode. 57 * The separator bars also needs to be sorted with the users for correct 58 * placement in the view or hidden if they are not used. 59 * 60 * To present a view with a custom list of contacts use a proxy model that 61 * filters items from the "All Users" special group. 62 * 63 * The classes holding the actual data for the contact list is located in 64 * contactlistdata.h as they are internal to the model and does not need to be 65 * visible to other classes. 66 */ 67 class ContactListModel : public QAbstractItemModel 68 { 69 Q_OBJECT 70 71 public: 72 73 /** 74 * Roles added for non visual data needed to use the contact list 75 */ 76 enum DataRole 77 { 78 ItemTypeRole = Qt::UserRole, // Type of item (one of enum ItemType) 79 NameRole, // Item name (alias for UserItems) 80 SortPrefixRole, // Primary sort index (UserItems only) 81 SortRole, // Sort index (secondary index for UserItems, only index for GroupItems) 82 UnreadEventsRole, // Number of unread events 83 EventTypeRole, // Type of event (UserItems only) 84 GroupIdRole, // Id for groups, parent groups for other items 85 SubGroupRole, // Sub group type (one of enum SubGroupType) (UserItems and BarItems only) 86 UserCountRole, // Number of users in this group (GroupItems and BarItems only) 87 UserIdRole, // Id for user (UserItems only) 88 AccountIdRole, // Account id for user (UserItems only) 89 PpidRole, // Protocol id for user (UserItems only) 90 StatusRole, // Contact status (UserItems only) 91 ExtendedStatusRole, // Various status flags needed by the delegate (UserItems only) 92 UserIconRole, // User picture for use as icon (UserItems only) 93 CarAnimationRole, // Auto response read animation counter (UserItems only) 94 OnlineAnimationRole, // Online animation counter (UserItems only) 95 EventAnimationRole, // Unread event animation counter (UserItems only) 96 VisibilityRole, // Item should always be visible 97 }; 98 99 /** 100 * Contact list item types (returned for ItemTypeRole) 101 */ 102 enum ItemType 103 { 104 InvalidItem = 0, 105 GroupItem, 106 BarItem, 107 UserItem 108 }; 109 110 /** 111 * Separator bar types (returned for SubGroupRole) 112 */ 113 enum SubGroupType 114 { 115 OnlineSubGroup = 0, 116 OfflineSubGroup, 117 NotInListSubGroup, 118 }; 119 120 /** 121 * Bit values for flags in ExtendedStatusRole data 122 * Mainly used for extended icons in delegate 123 */ 124 enum ExtendedStatusBit 125 { 126 PhoneStatusBit = 0, 127 CellularStatusBit, 128 BirthdayStatusBit, 129 InvisibleStatusBit, 130 GpgKeyStatusBit, 131 GpgKeyEnabledStatusBit, 132 PhoneFollowMeActiveStatusBit, 133 PhoneFollowMeBusyStatusBit, 134 IcqPhoneActiveStatusBit, 135 IcqPhoneBusyStatusBit, 136 SharedFilesStatusBit, 137 TypingStatusBit, 138 SecureStatusBit, 139 CustomArStatusBit, 140 IgnoreStatusBit, 141 OnlineNotifyStatusBit, 142 NotInListStatusBit, 143 InvisibleListStatusBit, 144 VisibleListStatusBit, 145 NewUserStatusBit, 146 AwaitingAuthStatusBit, 147 }; 148 static const unsigned long PhoneStatus = 1 << PhoneStatusBit; 149 static const unsigned long CellularStatus = 1 << CellularStatusBit; 150 static const unsigned long BirthdayStatus = 1 << BirthdayStatusBit; 151 static const unsigned long InvisibleStatus = 1 << InvisibleStatusBit; 152 static const unsigned long GpgKeyStatus = 1 << GpgKeyStatusBit; 153 static const unsigned long GpgKeyEnabledStatus = 1 << GpgKeyEnabledStatusBit; 154 static const unsigned long PhoneFollowMeActiveStatus = 1 << PhoneFollowMeActiveStatusBit; 155 static const unsigned long PhoneFollowMeBusyStatus = 1 << PhoneFollowMeBusyStatusBit; 156 static const unsigned long IcqPhoneActiveStatus = 1 << IcqPhoneActiveStatusBit; 157 static const unsigned long IcqPhoneBusyStatus = 1 << IcqPhoneBusyStatusBit; 158 static const unsigned long SharedFilesStatus = 1 << SharedFilesStatusBit; 159 static const unsigned long TypingStatus = 1 << TypingStatusBit; 160 static const unsigned long SecureStatus = 1 << SecureStatusBit; 161 static const unsigned long CustomArStatus = 1 << CustomArStatusBit; 162 static const unsigned long IgnoreStatus = 1 << IgnoreStatusBit; 163 static const unsigned long OnlineNotifyStatus = 1 << OnlineNotifyStatusBit; 164 static const unsigned long NotInListStatus = 1 << NotInListStatusBit; 165 static const unsigned long InvisibleListStatus = 1 << InvisibleListStatusBit; 166 static const unsigned long VisibleListStatus = 1 << VisibleListStatusBit; 167 static const unsigned long NewUserStatus = 1 << NewUserStatusBit; 168 static const unsigned long AwaitingAuthStatus = 1 << AwaitingAuthStatusBit; 169 170 // Constants for system groups 171 static const int SystemGroupOffset = 1000; 172 static const int OtherUsersGroupId = 0; 173 174 // "Normal" system groups 175 // Note: These constants are used by Config::Contactlist and written to config file 176 // Changing existing numbers will make old config files be read wrong 177 static const int OnlineNotifyGroupId = SystemGroupOffset + 0; 178 static const int VisibleListGroupId = SystemGroupOffset + 1; 179 static const int InvisibleListGroupId = SystemGroupOffset + 2; 180 static const int IgnoreListGroupId = SystemGroupOffset + 3; 181 static const int NewUsersGroupId = SystemGroupOffset + 4; 182 static const int AwaitingAuthGroupId = SystemGroupOffset + 5; 183 static const int NumSystemGroups = 6; 184 static const int LastSystemGroup = SystemGroupOffset + NumSystemGroups - 1; 185 static const int MostUsersGroupId = SystemGroupOffset + 100; 186 187 // Not real group but need unique id in menus 188 static const int AllGroupsGroupId = SystemGroupOffset + 101; 189 190 // Really all users. MostUsers above doesn't include Ignored users 191 static const int AllUsersGroupId = SystemGroupOffset + 200; 192 193 /** 194 * Get display name for system groups 195 * 196 * @param groupId Id of a system group 197 * @return Name of group 198 */ 199 static QString systemGroupName(int groupId); 200 201 /** 202 * Constructor 203 * Will get the current list from the daemon and connect to the signal manager for updates. 204 * 205 * @param parent Parent object 206 */ 207 ContactListModel(QObject* parent = 0); 208 209 /** 210 * Destructor 211 */ 212 virtual ~ContactListModel(); 213 214 /** 215 * Add a user to the contact list 216 * 217 * @param licqUser The user to add 218 */ 219 void addUser(const Licq::User* licqUser); 220 221 /** 222 * Remove a user from the contact list 223 * 224 * @param userId Licq user id 225 */ 226 void removeUser(const Licq::UserId& userId); 227 228 /** 229 * Get a model index for a group or user that other components can use. 230 * 231 * @param row Group index or user index within a group 232 * @param column A valid column for the model 233 * @param parent An existing group to get a user or an invalid model index to get a group 234 * @return A model index for the requested group or user 235 */ 236 virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; 237 238 /** 239 * Get the parent of a model index 240 * 241 * @param index An index for a group or user 242 * @return A group index if a user is provided or an invalid index if a group is provided 243 */ 244 virtual QModelIndex parent(const QModelIndex& index) const; 245 246 /** 247 * Get the number of groups or users in a group 248 * 249 * @param parent An index for a group or an invalid index 250 * @return The number of users in the group or the number of groups 251 */ 252 virtual int rowCount(const QModelIndex& parent) const; 253 254 /** 255 * Get the number of columns for a user or a group 256 * 257 * @param parent An index in the model 258 * @return The number of columns 259 */ 260 virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; 261 262 /** 263 * Get data for a user or a group 264 * 265 * @param index An index of a user or a group 266 * @param role The qt role to get data for 267 * @return The data for the given item and role 268 */ 269 virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; 270 271 /** 272 * Get item flags for an item 273 * 274 * @param index An index of a user or group 275 * @return The item flags for the user or group 276 */ 277 virtual Qt::ItemFlags flags(const QModelIndex& index) const; 278 279 /** 280 * Get header titles for the contact list 281 * 282 * @param section A column in the list 283 * @param orientation Specify the horizontal or vertical header 284 * @param role The qt role to get data for 285 * @return Header data for the given column and role 286 */ 287 virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 288 289 /** 290 * Set item data 291 * 292 * @param index Index for the item to update 293 * @param value Value to set 294 * @param role Role to update 295 */ 296 virtual bool setData(const QModelIndex& index, const QVariant& value, int role = ContactListModel::NameRole); 297 298 /** 299 * Get index for a specific user 300 * 301 * @param userId Licq user id 302 * @param column The column to return an index for 303 * @return An index for the given user and column from the "All Users" group 304 */ 305 QModelIndex userIndex(const Licq::UserId& userId, int column) const; 306 307 /** 308 * Get index for a group to use as root item for a view 309 * 310 * @param id Id of the group 311 * @return An index for the group or an invalid index if the group does not exist 312 */ 313 QModelIndex groupIndex(int id) const; 314 315 /** 316 * Get index for the All Users group 317 * 318 * @return Index for "All Users" group 319 */ allUsersGroupIndex()320 QModelIndex allUsersGroupIndex() const 321 { return groupIndex(AllUsersGroupId); } 322 323 /** 324 * Convenience function to get name of a group 325 * 326 * @param groupId Id of user group or system group 327 * @return Name of group 328 */ 329 QString groupName(int groupId) const; 330 331 public slots: 332 /** 333 * The daemon list has changed 334 * 335 * @param subSignal Sub signal telling what the change was 336 * @param argument Additional data, usage depend on sub signal type 337 * @param userId Id for affected user, if applicable 338 */ 339 void listUpdated(unsigned long subSignal, int argument, const Licq::UserId& userId); 340 341 /** 342 * The data for a user has changed in the daemon 343 * 344 * @param userId Id for affected user 345 * @param subSignal Sub signal telling what the change was 346 * @param argument Additional data, usage depend on sub signal type 347 */ 348 void userUpdated(const Licq::UserId& userId, unsigned long subSignal, int argument); 349 350 /** 351 * Reload the entire contact list from the daemon 352 */ 353 void reloadAll(); 354 355 private slots: 356 /** 357 * Update everything related to GUI configuration 358 */ 359 void configUpdated(); 360 361 /** 362 * The model data for a user has changed 363 * Will send a dataChanged signal for the user in all groups it is present 364 * 365 * @param user The user data object that has changed 366 */ 367 void userDataChanged(const ContactUserData* user); 368 369 /** 370 * The model data for a group has changed 371 * Will send a dataChanged signal for the group 372 * 373 * @param group The group object that has changed 374 */ 375 void groupDataChanged(ContactGroup* group); 376 377 /** 378 * The model data for a bar has changed 379 * Will send a dataChanged signal for the bar 380 * 381 * @param bar The bar object that has changed 382 * @param row The row of the bar in it's group 383 */ 384 void barDataChanged(ContactBar* bar, int row); 385 386 /** 387 * A group is about to add a user 388 * Will send beginInsertRow signal for the user 389 * 390 * @param group The group that's adding the user 391 * @param row The row the new user will have in the group 392 */ 393 void groupBeginInsert(ContactGroup* group, int row); 394 395 /** 396 * A group has finished adding a user 397 * Will send endInsertRow signal 398 */ 399 void groupEndInsert(); 400 401 /** 402 * A group is about to remove a user 403 * Will send beginRemoveRow signal for the user 404 * 405 * @param group The group that's removing the user 406 * @param row The row of the user about to be removed 407 */ 408 void groupBeginRemove(ContactGroup* group, int row); 409 410 /** 411 * A group has finished removing a user 412 * Will send endRemoveRow signal 413 */ 414 void groupEndRemove(); 415 416 /** 417 * Update the user membership in all groups 418 * This is triggered by the user data object when its group membership (may) have changed 419 * 420 * @param user The model user to update groups for 421 * @param licqUser The daemon user to get group membership from 422 */ 423 void updateUserGroups(ContactUserData* user, const Licq::User* licqUser); 424 425 private: 426 /** 427 * Connect signals for a newly created group object 428 * 429 * @param group Group object to connect signals from 430 */ 431 void connectGroup(ContactGroup* group); 432 433 /** 434 * Get the user object that represents an licq contact 435 * 436 * @param userId Licq user id 437 * @return The user object or NULL if it was not found 438 */ 439 ContactUserData* findUser(const Licq::UserId& userId) const; 440 441 /** 442 * Check if a user is member of a group and add/remove the user to/from the group if needed 443 * 444 * @param user The user to update 445 * @param group The group to check 446 * @param shouldBeMember True to add the user if missing or false to remove if member 447 */ 448 void updateUserGroup(ContactUserData* user, ContactGroup* group, bool shouldBeMember); 449 450 /** 451 * Get model row for a group 452 * 453 * @param group A group object 454 * @return Row in model or -1 if not found 455 */ 456 int groupRow(ContactGroup* group) const; 457 458 QList<ContactGroup*> myGroups; 459 ContactGroup* myAllUsersGroup; 460 QList<ContactUserData*> myUsers; 461 int myColumnCount; 462 bool myBlockUpdates; 463 }; 464 465 extern ContactListModel* gGuiContactList; 466 467 } // namespace LicqQtGui 468 469 #endif 470