📄 groupmanager.mm
字号:
/*
* LumaQQ - Cross platform QQ client, special edition for Mac
*
* Copyright (C) 2007 luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#import "GroupManager.h"
#import "PreferenceConstants.h"
#import "PreferenceManager.h"
#import "FriendGroup.h"
#import "UserProperty.h"
#import "Signature.h"
#import "SubCluster.h"
#import "QQConstants.h"
#import "Member.h"
#import "PreferenceCache.h"
#import "LocalizedStringTool.h"
#import "FileTool.h"
#import "Constants.h"
#define _kKeyFriendlyGroups @"FriendlyGroup"
#define _kKeyStrangerGroup @"StrangerGroup"
#define _kKeyBlacklistGroup @"BlacklistGroup"
#define _kKeyClusterGroup @"ClusterGroup"
#define _kKeyMobileGroup @"MobileGroup"
#define _kKeyRecentContacts @"RecentContacts"
#define _kKeyDialogs @"Dialogs"
@implementation GroupManager
- (id) init {
NSException* e = [NSException exceptionWithName:@"InitializationException"
reason:@"Don't use init of GroupManager"
userInfo:nil];
[e raise];
return nil;
}
- (id)initWithQQ:(UInt32)QQ domain:(MainWindowController*)domain {
self = [super init];
if (self != nil) {
m_domain = [domain retain];
m_QQ = QQ;
m_dirty = NO;
m_changed = NO;
m_userRegistry = [[NSMutableDictionary dictionary] retain];
m_clusterRegistry = [[NSMutableDictionary dictionary] retain];
m_tempClusterRegistry = [[NSMutableDictionary dictionary] retain];
m_mobileRegistry = [[NSMutableDictionary dictionary] retain];
m_dialogsDummy = [[Dummy alloc] initWithType:kDummyDialogs name:L(@"LQDialogs")];
m_recentContacts = [[NSMutableArray array] retain];
// create me
m_me = [[User alloc] initWithQQ:QQ domain:m_domain];
[m_userRegistry setObject:m_me forKey:[NSNumber numberWithUnsignedInt:QQ]];
}
return self;
}
- (void) dealloc {
[m_domain release];
[m_groups release];
[m_strangerGroup release];
[m_blacklistGroup release];
[m_clusterGroup release];
[m_mobileGroup release];
[m_userRegistry release];
[m_clusterRegistry release];
[m_mobileRegistry release];
[m_tempClusterRegistry release];
[m_dialogsDummy release];
[m_dialogs release];
[m_recentContacts release];
[m_me release];
[super dealloc];
}
#pragma mark -
#pragma mark load/save/initialize
- (void)loadGroups {
// get path
NSString* sFilePath = [FileTool getFilePath:m_QQ ForFile:kLQFileGroups];
NSData* data = [NSData dataWithContentsOfFile:sFilePath];
if(data) {
NSKeyedUnarchiver* unar = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
m_groups = [[unar decodeObjectForKey:_kKeyFriendlyGroups] retain];
m_strangerGroup = [[unar decodeObjectForKey:_kKeyStrangerGroup] retain];
m_blacklistGroup = [[unar decodeObjectForKey:_kKeyBlacklistGroup] retain];
m_clusterGroup = [[unar decodeObjectForKey:_kKeyClusterGroup] retain];
m_mobileGroup = [[unar decodeObjectForKey:_kKeyMobileGroup] retain];
m_recentContacts = [[unar decodeObjectForKey:_kKeyRecentContacts] retain];
m_dialogs = [[unar decodeObjectForKey:_kKeyDialogs] retain];
[unar finishDecoding];
[unar release];
// check error
if(m_groups == nil ||
m_strangerGroup == nil ||
m_blacklistGroup == nil ||
m_clusterGroup == nil ||
m_recentContacts == nil ||
m_mobileGroup == nil ||
m_dialogs == nil) {
// release all and renew
[m_groups release];
[m_strangerGroup release];
[m_blacklistGroup release];
[m_clusterGroup release];
[m_mobileGroup release];
[m_recentContacts release];
[m_dialogs release];
m_groups = nil;
m_strangerGroup = nil;
m_blacklistGroup = nil;
m_clusterGroup = nil;
m_mobileGroup = nil;
m_recentContacts = nil;
m_dialogs = nil;
[self initializeGroups:[NSArray array]];
} else {
// hash users and clusters
NSEnumerator* groupEnum = [m_groups objectEnumerator];
while(Group* g = [groupEnum nextObject]) {
[self registerGroup:g];
}
[self registerGroup:m_strangerGroup];
[self registerGroup:m_blacklistGroup];
[self registerGroup:m_clusterGroup];
[self registerGroup:m_mobileGroup];
NSEnumerator* e = [m_recentContacts objectEnumerator];
while(id obj = [e nextObject]) {
if([obj isMemberOfClass:[User class]]) {
User* u = (User*)obj;
[u setDomain:m_domain];
[m_userRegistry setObject:u forKey:[NSNumber numberWithUnsignedInt:[u QQ]]];
} else if([obj isMemberOfClass:[Cluster class]]) {
Cluster* c = (Cluster*)obj;
[c setDomain:m_domain];
if([c permanent])
[m_clusterRegistry setObject:c forKey:[NSNumber numberWithUnsignedInt:[c internalId]]];
else
[m_tempClusterRegistry setObject:c forKey:[NSNumber numberWithUnsignedInt:[c internalId]]];
} else if([obj isMemberOfClass:[Mobile class]]) {
Mobile* m = (Mobile*)obj;
[m setDomain:m_domain];
[m_mobileRegistry setObject:m forKey:[m mobile]];
}
}
e = [m_dialogs objectEnumerator];
while(Cluster* dialog = [e nextObject]) {
[dialog setDomain:m_domain];
[m_tempClusterRegistry setObject:dialog forKey:[NSNumber numberWithUnsignedInt:[dialog internalId]]];
}
}
} else
[self initializeGroups:[NSArray array]];
}
- (void)saveGroups {
if(!m_dirty)
return;
m_dirty = NO;
// get path
NSString* sFilePath = [FileTool getFilePath:m_QQ ForFile:kLQFileGroups];
// save to file
NSMutableData* data = [NSMutableData data];
NSKeyedArchiver* ar = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[ar setOutputFormat:NSPropertyListXMLFormat_v1_0];
[ar encodeObject:m_groups forKey:_kKeyFriendlyGroups];
[ar encodeObject:m_strangerGroup forKey:_kKeyStrangerGroup];
[ar encodeObject:m_blacklistGroup forKey:_kKeyBlacklistGroup];
[ar encodeObject:m_clusterGroup forKey:_kKeyClusterGroup];
[ar encodeObject:m_mobileGroup forKey:_kKeyMobileGroup];
[ar encodeObject:m_recentContacts forKey:_kKeyRecentContacts];
[ar encodeObject:m_dialogs forKey:_kKeyDialogs];
[ar finishEncoding];
[data writeToFile:sFilePath atomically:YES];
}
- (void)registerGroup:(Group*)g {
NSEnumerator* e = nil;
if([g isUser]) {
e = [g userEnumerator];
while(User* u = [e nextObject]) {
[u setDomain:m_domain];
[m_userRegistry setObject:u forKey:[NSNumber numberWithUnsignedInt:[u QQ]]];
}
} else if([g isCluster]) {
e = [g clusterEnumerator];
while(Cluster* c = [e nextObject]) {
[c setDomain:m_domain];
[m_clusterRegistry setObject:c forKey:[NSNumber numberWithUnsignedInt:[c internalId]]];
NSEnumerator* scEnum = [c subClusterEnumerator];
while(Cluster* sc = [scEnum nextObject]) {
[sc setDomain:m_domain];
[m_tempClusterRegistry setObject:sc forKey:[NSNumber numberWithUnsignedInt:[sc internalId]]];
}
}
} else {
e = [g mobileEnumerator];
while(Mobile* m = [e nextObject]) {
[m setDomain:m_domain];
[m_mobileRegistry setObject:m forKey:[m mobile]];
}
}
}
//
// initialize groups, this will clear all groups and reconstruct them again
// not including "stranger" and "blacklist"
//
- (void)initializeGroups:(NSArray*)groupNames {
// create
if(m_groups == nil)
m_groups = [[NSMutableArray array] retain];
if(m_strangerGroup == nil)
m_strangerGroup = [[Group alloc] initWithFlag:kGroupUser name:L(@"LQGroupStranger")];
if(m_blacklistGroup == nil)
m_blacklistGroup = [[Group alloc] initWithFlag:(kGroupUser | kGroupBlacklist) name:L(@"LQGroupBlacklist")];
if(m_clusterGroup == nil)
m_clusterGroup = [[Group alloc] initWithFlag:kGroupCluster];
if(m_mobileGroup == nil)
m_mobileGroup = [[Group alloc] initWithFlag:kGroupMobile];
if(m_recentContacts == nil)
m_recentContacts = [[NSMutableArray array] retain];
if(m_dialogs == nil)
m_dialogs = [[NSMutableArray array] retain];
// clean
[m_groups removeAllObjects];
// reset user group index
NSEnumerator* e = [[m_userRegistry allValues] objectEnumerator];
while(User* u = [e nextObject]) {
[u setGroupIndex:kGroupIndexUndefined];
}
// add me
[m_userRegistry setObject:m_me forKey:[NSNumber numberWithUnsignedInt:m_QQ]];
// add my friends group
if([m_groups count] == 0) {
Group* g = [[Group alloc] initWithFlag:(kGroupUser | kGroupFriendly) name:L(@"LQGroupMyFriends")];
[m_groups addObject:g];
[g release];
}
// add normal friendly group
int count = [m_groups count];
int nameCount = [groupNames count];
for(int i = 0; i < nameCount; i++) {
// get group object or create a new one
Group* g = nil;
if(i + 1 < count)
g = [self group:(i + 1)];
else {
g = [[Group alloc] init];
[m_groups addObject:g];
[g release];
}
// set group name
[g setName:[groupNames objectAtIndex:i]];
}
}
#pragma mark -
#pragma mark getter and setter
- (UInt32)QQ {
return m_QQ;
}
- (NSArray*)recentContacts {
return m_recentContacts;
}
- (Group*)group:(int)index {
if(index < 0)
return nil;
// if index exceed user friendly group, return others
int count = [m_groups count];
if(index >= count) {
switch(index - count) {
case 0:
return m_strangerGroup;
case 1:
return m_blacklistGroup;
case 2:
return m_clusterGroup;
case 3:
return m_mobileGroup;
default:
return nil;
}
} else
return [m_groups objectAtIndex:index];
}
- (Group*)clusterGroup {
return m_clusterGroup;
}
- (Group*)strangerGroup {
return m_strangerGroup;
}
- (Group*)blacklistGroup {
return m_blacklistGroup;
}
- (Group*)mobileGroup {
return m_mobileGroup;
}
#pragma mark -
#pragma mark sort
- (void)sortAll {
NSEnumerator* e = [m_groups objectEnumerator];
Group* g = nil;
while(g = [e nextObject])
[g sort];
}
#pragma mark -
#pragma mark user type check
- (BOOL)isUserFriendly:(User*)user {
Group* g = [self group:[user groupIndex]];
return g != nil && [g isUser] && [g isFriendly];
}
- (BOOL)isUserStranger:(User*)user {
Group* g = [self group:[user groupIndex]];
return g == nil || [g isUser] && [g isStranger];
}
- (BOOL)isUserBlacklist:(User*)user {
Group* g = [self group:[user groupIndex]];
return g != nil && [g isBlacklist];
}
#pragma mark -
#pragma mark edit methods
- (void)removeRecentContactAtIndex:(int)index {
if(index < 0 || index >= [m_recentContacts count])
return;
[m_recentContacts removeObjectAtIndex:index];
m_dirty = YES;
}
- (void)removeAllRecentContacts {
[m_recentContacts removeAllObjects];
m_dirty = YES;
}
- (void)addRecentContact:(id)object {
// try remove it
[m_recentContacts removeObject:object];
// remove last contact
PreferenceCache* cache = [PreferenceCache cache:m_QQ];
while([m_recentContacts count] >= [cache maxRecentContact])
[m_recentContacts removeLastObject];
// add to first
[m_recentContacts insertObject:object atIndex:0];
// add to registry
if([object isMemberOfClass:[User class]]) {
id key = [NSNumber numberWithUnsignedInt:[(User*)object QQ]];
if(![m_userRegistry objectForKey:key])
[m_userRegistry setObject:object forKey:key];
} else if([object isMemberOfClass:[Cluster class]]) {
id key = [NSNumber numberWithUnsignedInt:[(Cluster*)object internalId]];
if(![m_clusterRegistry objectForKey:key])
[m_clusterRegistry setObject:object forKey:key];
}
// dirty flag
m_dirty = YES;
}
- (void)addFriendGroups:(NSArray*)friendGroups {
NSEnumerator* e = [friendGroups objectEnumerator];
FriendGroup* fg = nil;
while(fg = [e nextObject]) {
// get group object
Group* g = [fg isUser] ? [self group:[fg groupIndex]] : [self clusterGroup];
// create user or cluster
if([g isUser]) {
if([fg QQ] == m_QQ) {
[g addUser:[self user:m_QQ]];
[[self user:m_QQ] setGroupIndex:[fg groupIndex]];
} else {
User* u = [m_userRegistry objectForKey:[NSNumber numberWithUnsignedInt:[fg QQ]]];
if(u == nil)
u = [[[User alloc] initWithQQ:[fg QQ] domain:m_domain] autorelease];
if([g addUser:u]) {
// set group index
[u setGroupIndex:[fg groupIndex]];
// add to registry
[m_userRegistry setObject:u forKey:[NSNumber numberWithUnsignedInt:[u QQ]]];
}
}
} else {
Cluster* c = [m_clusterRegistry objectForKey:[NSNumber numberWithUnsignedInt:[fg QQ]]];
if(c == nil)
c = [[[Cluster alloc] initWithInternalId:[fg QQ] domain:m_domain] autorelease];
if([g addCluster:c]) {
// add to registry
[m_clusterRegistry setObject:c forKey:[NSNumber numberWithUnsignedInt:[c internalId]]];
}
}
// set dirty flag
m_dirty = YES;
}
}
- (void)addFriends:(NSArray*)friends {
NSEnumerator* e = [friends objectEnumerator];
Friend* f = nil;
while(f = [e nextObject]) {
User* u = [self user:[f QQ]];
if(u) {
[u copyWithFriend:f];
m_dirty = YES;
}
}
}
- (void)setUserProperty:(NSArray*)properties {
NSEnumerator* e = [properties objectEnumerator];
UserProperty* prop = nil;
while(prop = [e nextObject]) {
User* u = [self user:[prop QQ]];
if(u) {
[u copyWithUserProperty:prop];
}
}
}
- (void)setFriendLevel:(NSArray*)levels {
NSEnumerator* e = [levels objectEnumerator];
FriendLevel* level = nil;
while(level = [e nextObject]) {
User* u = [self user:[level QQ]];
if(u) {
[u copyWithFriendLevel:level];
}
}
}
- (void)setSignature:(NSArray*)signatures {
NSEnumerator* e = [signatures objectEnumerator];
Signature* sig = nil;
while(sig = [e nextObject]) {
User* u = [self user:[sig QQ]];
if(u) {
[u copyWithSignature:sig];
}
}
}
- (void)setRemarks:(NSArray*)remarks {
NSEnumerator* e = [remarks objectEnumerator];
FriendRemark* remark = nil;
while(remark = [e nextObject]) {
User* u = [self user:[remark QQ]];
if(u) {
[u copyWithRemarks:remark];
m_dirty = YES;
}
}
}
- (void)setClusterInfo:(ClusterInfo*)info {
Cluster* c = [self cluster:[info internalId]];
if(c) {
[c setClusterInfo:info];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -