📄 messagehelper.java
字号:
return;
} else {
GroupModel g = (GroupModel)model.getTab(indices[0]);
if(!g.isFriendly()) {
log.debug("设置了拒绝陌生人消息,忽略该消息");
return;
}
}
} else {
// 在陌生人组中为它分配一个序号
if(indices == null || indices.length == 0)
indices = mvcHelper.getStrangerIndex(packet.normalHeader.sender);
}
} else {
GroupModel g = (GroupModel)model.getTab(indices[0]);
if(g.isBlackList()) {
model.removeItem(indices[0], indices[1]);
indices = mvcHelper.getStrangerIndex(packet.normalHeader.sender);
}
}
Shutter shutter = main.getShutter();
ShellRegistry shellRegistry = main.getShellRegistry();
MessageQueue mq = main.getMessageQueue();
UIHelper uiHelper = main.getUIHelper();
ReplyUtil replies = ReplyUtil.getInstance();
QQClient client = main.getClient();
Integer qqNum = new Integer(packet.normalHeader.sender);
// 得到好友的view control,也就是ShutterLabel,以及从control的data属性得到model
CoolButton viewPart = shutter.getItemControl(indices[0], indices[1]);
CoolButton tab = shutter.getTabControl(indices[0]);
FriendModel f = (FriendModel)model.getItem(indices[0], indices[1]);
// 如果最近联系人功能是打开的,添加到最近联系人中
if(options.isEnableLatest() && (!isStranger || (isStranger && options.isKeepStrangerInLatest()))) {
// 得到最近联系人组,如果没有最近联系人这个组,则新建一个
int[] i = mvcHelper.listLatestGroup();
if(i == null || i.length == 0) {
main.getMVCHelper().createLatestGroup();
i = new int[] { model.getTabCount() - 1 };
}
// 得到最近联系人设定最大数量
int max = options.getLatestSize();
// 得到当前联系人数量
int num = model.getItemCount(i[0]);
// 删除多余的联系人
if(max > 0) {
while(num >= max)
model.removeItem(i[0], --num);
// 如果没有这个人,添加
int[] temp = mvcHelper.listFriend(i[0], f.getQQ(), false);
if(temp == null || temp.length == 0) {
FriendModel cf = f.cloneProperties();
cf.addProperty(IQQNode.ORIGINAL, "false");
model.addItem(i[0], cf);
}
}
}
// 在这里要检查好友的发送消息状态,如果在这个时候,好友的发送消息窗口是打开的
// 并且与好友处于聊天模式中,那么就直接把这个消息推到这个窗口,而不需要再
// 闪烁图标了
if(shellRegistry.hasSendIMWindow(f) && f.isTalkMode()) {
// 得到发送消息窗口实例
SendIMWindow sms = shellRegistry.getSendIMWindow(f);
// 在把这条消息推入窗口之前,我们还需要检查是否之前还有这个好友的消息,这种情况是
// 可能的,发生在用户开始处于消息模式,后来处于聊天模式,而这之间有消息未读时
while(mq.hasMessage(qqNum)) {
ReceiveIMPacket p = (ReceiveIMPacket)mq.getMessage(qqNum);
sms.appendMessage(f, p.normalIM, p.normalHeader);
}
// 现在轮到把这条消息推入窗口中了
sms.appendMessage(f, packet.normalIM, packet.normalHeader);
// 停止跳动和闪烁头像
viewPart.stopBounceImage();
uiHelper.resetGroupImageEffect(indices[0]);
uiHelper.resetTrayImageEffect();
// 如果聊天窗口当前不是active的,闪烁图标并播放声音提示用户有消息到来
if(!sms.isActive()) {
sms.startBlinkImage();
main.getSoundDaemon().play(LumaQQ.MSG_SOUND);
}
return;
}
// 修改好友的是否有消息属性,这个属性主要用于排序,也就是如果一个好友是隐身的
// 那么一般他在排在下面,需要翻页才能看到,很不方便,所以通过设置这个属性,
// 能够让好友有消息来时排到列表的最前面,方便用户选择查看消息
if(f.isOffline()) {
// 如果好友当前是离线状态,临时设置他的状态为在线
main.setFriendProperty(f, IQQNode.STATUS, IQQNode.VALUE_ONLINE);
// 把好友加入到当前在线名单
main.getCurrentOnlines().add(f);
}
main.setFriendProperty(f, IQQNode.HAS_MESSAGE, "true");
// 从model得到好友的头像
Image face = HeadFactory.getOnlineHead(f);
// 检查这是否是第一个消息,如果是,则需要闪烁tray icon,同时还要
// 在tab上闪烁图标,还要在friend上跳动一个图标,如果不是,则
// 不需要闪动tray icon,但是其他两个还是要的。如果当前好友已经
// 有其他消息还没有读,则声音提示就免掉
if(!mq.hasNext())
uiHelper.startBlinkImage(HeadFactory.getOnlineSmallHead(f));
if(!tab.isBlinking())
tab.startBlinkImage(face);
if(!viewPart.isBouncing()) {
viewPart.startBounceImage(face);
main.getSoundDaemon().play(LumaQQ.MSG_SOUND);
}
// 推入队列
mq.putMessage(packet, tab);
log.debug("新的普通消息被推入队列");
// 检查是否这个好友的消息窗口已经被打开,如果是,使下一条按钮使能
if(shellRegistry.hasReceiveIMWindow(f)) {
ReceiveIMWindow rms = shellRegistry.getReceiveIMWindow(f);
rms.setNextButtonEnabled(true);
}
// 检查当前是否在离开状态,并且是否设置了自动回复,如果是,自动回复消息
if(client.getUser().getStatus() == QQ.QQ_FRIEND_STATUS_AWAY
&& packet.normalIM.replyType != QQ.QQ_IM_AUTO_REPLY
&& replies.isAutoReply()) {
client.sendIM(packet.normalHeader.sender, replies.getCurrentAutoReplyString(), QQ.QQ_IM_AUTO_REPLY);
log.debug("自动回复消息已发送");
}
// 检查是否设置了自动弹出消息且当前没有打开的查看消息窗口,则自动弹出
// 如果没有设置自动弹出,且目前主窗口处于最小化状态,显示消息提示
if(!shellRegistry.hasReceiveIMWindow(f)) {
if(options.isAutoEject())
main.getShellLauncher().openNormalIMWindow(viewPart);
}
}
/**
* 推入一条群消息并更新各种图标的闪烁状态,如果好友列表还没有全部得到,
* 则推入延迟队列
*
* @param packet
* 消息包对象
* @param resolved
* true表示其中的自定义表情都已经得到
*/
public void putClusterIM(ReceiveIMPacket packet) {
MessageQueue mq = main.getMessageQueue();
ShellRegistry shellRegistry = main.getShellRegistry();
SoundDaemon soundDaemon = main.getSoundDaemon();
// 检查好友列表是否完全得到
if(main.isFriendListFinished()) {
// 得到群的内部ID
int clusterId = packet.header.sender;
if(packet.header.type == QQ.QQ_RECV_IM_TEMP_CLUSTER_IM)
clusterId = packet.clusterIM.clusterId;
// 得到群的model。如果没有,则新建一个
ClusterModel c = null;
if(packet.header.type == QQ.QQ_RECV_IM_TEMP_CLUSTER_IM)
c = main.getMVCHelper().addTempCluster(packet.clusterIM.type, clusterId, packet.clusterIM.externalId);
else
c = main.getMVCHelper().addCluster(clusterId, false);
if(c == null) return;
// 如果群消息发送者是我自己,则不处理这条消息
if(main.getMyModel().getQQ() == packet.clusterIM.sender) return;
// 得到消息设定,如果设置了阻止群消息,返回
String messageOption = c.getMessageOption();
if(IQQNode.VALUE_BLOCK == messageOption)
return;
// 如果这个消息是分片消息,如果这个消息已经完成,则继续处理,否则推入分片缓冲
if(!packet.clusterIM.faceResolved && isFragment(packet.clusterIM)) {
addFragment(packet.clusterIM);
if(isMessageComplete(packet.clusterIM.messageId)) {
packet.clusterIM = getIntegratedClusterIM(packet.clusterIM.messageId);
} else {
return;
}
}
// 检查消息里面是否有自定义表情,如果是,提交给自定义表情接收器,返回
if(!packet.clusterIM.faceResolved) {
if(packet.clusterIM.message == null)
packet.clusterIM.message = convertBytes(packet.clusterIM.messageBytes);
if(packet.clusterIM.message.indexOf(IRichContent.CUSTOM_FACE_TAG) != -1) {
main.getFaceReceiver().addClusterIM(packet);
return;
}
}
// 检查versionId,如果不符合,更新群信息
if(c.isClusterDirty(packet.clusterIM.versionId)) {
c.setVersionId(packet.clusterIM.versionId);
if(c.isPermanent())
main.getClient().getClusterInfo(clusterId);
else
main.getClient().getTempClusterInfo(c.getType(), clusterId, c.getParentClusterId());
}
// 保存到聊天记录
main.getMessageManager().saveMessage(clusterId, clusterId, packet.clusterIM.sender, packet.clusterIM.message, (int)(packet.clusterIM.sendTime / 1000L));
// 得到群组的索引和这个群组的view part
int cgIndex = main.getMVCHelper().getFirstClusterGroup();
CoolButton tab = main.getShutter().getTabControl(cgIndex);
// 如果这个群的聊天窗口当前处于打开状态,则把消息直接推入,但是也是有一个例外
// 就是用户设置了阻止该群的一切消息时。
// 如果这个群的聊天窗口没有打开,则要根据用户的设置来判断动作
if(shellRegistry.hasSendClusterIMWindow(c)) {
if(!IQQNode.VALUE_BLOCK.equals(messageOption)) {
// 得到发送消息窗口实例
SendClusterIMWindow scms = shellRegistry.getSendClusterIMWindow(c);
// 把这条消息推入窗口中
scms.appendMessage(c, packet.clusterIM, false);
// 如果窗口不是active的,闪烁图标并播放声音提醒用户
// 目前禁止声音提示,有些用户觉得群窗口打开时播放声音太烦
if(!scms.isActive()) {
scms.startBlinkImage();
//soundDaemon.play(LumaQQ.MSG_SOUND);
}
}
} else {
if(IQQNode.VALUE_ACCEPT.equals(messageOption)) {
// 检查这是否是第一个消息,如果是,则需要闪烁tray icon,同时还要
// 在tab上闪烁图标,还要在群上跳动一个图标,如果不是,则
// 不需要闪动tray icon,但是其他两个还是要的。如果当前群有
// 消息未读,则不播放提示声音
CoolButton viewPart = main.getMVCHelper().getClusterViewPart(clusterId);
if(!mq.hasNext())
main.getUIHelper().startBlinkImage(icons.getSmallClusterHead(c.getFaceId()));
if(!tab.isBlinking())
tab.startBlinkImage(c.getImage());
if(!viewPart.isBouncing()) {
viewPart.startBounceImage(c.getImage());
// 播放消息提示声音
soundDaemon.play(LumaQQ.MSG_SOUND);
}
// 推入队列
mq.putMessage(packet, tab);
} else if(IQQNode.VALUE_EJECT.equals(messageOption)) {
// 推入队列
mq.putMessage(packet, tab);
// 弹出窗口
main.getShellLauncher().openClusterIMWindow(c);
// 播放消息提示声音
soundDaemon.play(LumaQQ.MSG_SOUND);
} else if(IQQNode.VALUE_SHOW_NUMBER.equals(messageOption)) {
// 推入队列
mq.putMessage(packet, tab, false);
}
// 消息数增1
c.increaseMessageCount();
}
} else {
log.debug("好友列表未完全得到,延迟处理该群消息");
mq.postponeMessage(packet);
}
}
/**
* 推入一个系统消息并更新动画,这个比较简单,如果系统消息按钮没有闪烁就闪烁它
* 如果这是第一个消息,则tray icon也要闪烁,其他没什么要判断的了
*
* @param packet
* 系统通知包
*/
public void putSystemNotificationAndUpdateAnimate(SystemNotificationPacket packet) {
// 保存到聊天记录,系统通知一概做为10000的QQ号存入,其中消息部分有些特殊
// 分成两个域,第一个是消息类型字节,第二个是消息内容,用|分隔,这只
// 是个权宜之计,因为我匆匆定义的聊天记录格式比较土
StringBuffer sb = new StringBuffer();
String qq = String.valueOf(packet.from);
sb.append((int)packet.type);
sb.append('|');
if(packet.type == QQ.QQ_MSG_SYS_BEING_ADDED)
sb.append(LumaQQ.getString("receive.system.message.addme", new Object[] { qq }));
else if(packet.type == QQ.QQ_MSG_SYS_ADD_FRIEND_REQUEST)
sb.append(LumaQQ.getString("receive.system.message.request", new Object[] { qq, packet.message }));
else if(packet.type == QQ.QQ_MSG_SYS_ADD_FRIEND_APPROVED)
sb.append(LumaQQ.getString("receive.system.message.approved", new Object[] { qq }));
else if(packet.type == QQ.QQ_MSG_SYS_ADD_FRIEND_REJECTED)
sb.append(LumaQQ.getString("receive.system.message.rejected", new Object[] { qq, packet.message }));
main.getMessageManager().saveMessage(10000, packet.from, packet.from, sb.toString(), (int)(System.currentTimeMillis() / 1000));
// 调整动画状态
if(!main.getMessageQueue().hasNext())
main.getUIHelper().startBlinkImage(icons.getImage(IconHolder.icoSysMsg));
if(!main.isSystemMessageIconBlinking())
main.startBlinkSystemMessageIcon();
main.getMessageQueue().putSystemMessage(packet);
// 播放声音
main.getSoundDaemon().play(LumaQQ.SYS_MSG_SOUND);
log.debug("一个系统消息被推入队列");
}
/**
* 把一个短信推入消息队列
*
* @param packet
* 短消息包
*/
public void putSMS(ReceiveIMPacket packet) {
// 保存到聊天记录中
main.getMessageManager().saveMessage(packet.header.sender, packet.header.sender, packet.header.sender, packet.sms.message, (int)(System.currentTimeMillis() / 1000));
// 得到好友在model中的位置,但是有可能为null,因为也许这是用户的第一次登陆
// 其好友列表还没得到,但是这时候有消息来了,所有也无法闪烁图标了,对于
// 这种情况,需要特殊处理一下,基本的方法是把消息推入延迟处理队列
int[] indices = main.getMVCHelper().getFriendCoordinate(packet.header.sender);
if((indices == null || indices.length == 0) && !main.isFriendListFinished()) {
main.getMessageQueue().postponeMessage(packet);
log.debug("发来短信的好友还未出现在好友列表中,延迟处理该短信");
return;
} else {
// 检查这是否是第一个消息,如果是,则需要闪烁tray icon
// 同时检查是否第一条短信,如果是,需要闪烁按钮
if(!main.getMessageQueue().hasNext())
main.getUIHelper().startBlinkImage(icons.getImage(IconHolder.icoMobile));
if(!main.isSMSIconBlinking())
main.startBlinkSMSIcon();
// 播放声音
main.getSoundDaemon().play(LumaQQ.MSG_SOUND);
// 推入队列
main.getMessageQueue().putSMS(packet);
log.debug("新的手机短信被推入队列");
// 检查是否短消息接收窗口已经被打开,如果是,使下一条按钮使能
if(main.getShellRegistry().isReceiveSMSShellOpened())
main.getShellRegistry().getReceiveSMSShell().setNextButtonEnabled(true);
}
}
/**
* 把对方的文件传输请求推入到发送消息窗口中
*
* @param packet
* ReceiveIMPacket对象
*/
public void putSendFileRequestIM(ReceiveIMPacket packet) {
// 得到发送窗口的实例,如果没有就创建一个,并设置为聊天模式
FriendModel f = main.getMVCHelper().getFriendModel(packet.normalHeader.sender);
SendIMWindow sms = null;
if(main.getShellRegistry().hasSendIMWindow(f)) {
sms = main.getShellRegistry().getSendIMWindow(f);
if(!sms.isTalkMode()) sms.setTalkMode(true);
sms.setMinimized(false);
sms.setActive();
} else {
sms = ShellFactory.createSendIMWindow(main, f);
sms.setTalkMode(true);
}
// 打开窗口
sms.open();
// 把请求传送文件的源包传递给窗口
sms.setRequestPacket(packet);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -