📄 mainshell.java
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 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
*/
package edu.tsinghua.lumaqq.shells;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import edu.tsinghua.lumaqq.IMessage;
import edu.tsinghua.lumaqq.IPSeeker;
import edu.tsinghua.lumaqq.IconHolder;
import edu.tsinghua.lumaqq.LumaQQ;
import edu.tsinghua.lumaqq.LumaQQMessageManager;
import edu.tsinghua.lumaqq.MessageEntry;
import edu.tsinghua.lumaqq.MessageQueue;
import edu.tsinghua.lumaqq.ModelUtils;
import edu.tsinghua.lumaqq.QQShowManager;
import edu.tsinghua.lumaqq.SoundDaemon;
import edu.tsinghua.lumaqq.events.ClusterPropertyListener;
import edu.tsinghua.lumaqq.events.FriendDragSourceListener;
import edu.tsinghua.lumaqq.events.FriendPropertyListener;
import edu.tsinghua.lumaqq.events.GroupDropTargetListener;
import edu.tsinghua.lumaqq.events.GroupMouseListener;
import edu.tsinghua.lumaqq.events.GroupPropertyListener;
import edu.tsinghua.lumaqq.events.ItemMouseListener;
import edu.tsinghua.lumaqq.events.ItemMouseTrackListener;
import edu.tsinghua.lumaqq.events.LumaQQModelListener;
import edu.tsinghua.lumaqq.events.QQShowEvent;
import edu.tsinghua.lumaqq.events.QQShowListener;
import edu.tsinghua.lumaqq.models.BlacklistMatcher;
import edu.tsinghua.lumaqq.models.ClusterIdMatcher;
import edu.tsinghua.lumaqq.models.ClusterMatcher;
import edu.tsinghua.lumaqq.models.ClusterModel;
import edu.tsinghua.lumaqq.models.FriendModel;
import edu.tsinghua.lumaqq.models.FriendlyMatcher;
import edu.tsinghua.lumaqq.models.GroupModel;
import edu.tsinghua.lumaqq.models.ModelSorter;
import edu.tsinghua.lumaqq.models.QQNumberMatcher;
import edu.tsinghua.lumaqq.models.StrangerMatcher;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.Utils;
import edu.tsinghua.lumaqq.qq.beans.ClusterInfo;
import edu.tsinghua.lumaqq.qq.beans.ContactInfo;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.events.QQListener;
import edu.tsinghua.lumaqq.qq.packets.InPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ClusterCommandReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetUserInfoReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ReceiveIMPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SystemNotificationPacket;
import edu.tsinghua.lumaqq.qq.packets.out.DownloadGroupFriendPacket;
import edu.tsinghua.lumaqq.qq.packets.out.GroupNameOpPacket;
import edu.tsinghua.lumaqq.qq.packets.out.UploadGroupFriendPacket;
import edu.tsinghua.lumaqq.utils.OptionUtils;
import edu.tsinghua.lumaqq.utils.ProxyUtils;
import edu.tsinghua.lumaqq.utils.RemarkUtils;
import edu.tsinghua.lumaqq.utils.ReplyUtils;
import edu.tsinghua.lumaqq.widgets.ClusterMessageExporter;
import edu.tsinghua.lumaqq.widgets.FriendMessageExporter;
import edu.tsinghua.lumaqq.widgets.IRecordExporter;
import edu.tsinghua.lumaqq.xml.groups.Cluster;
import edu.tsinghua.lumaqq.xml.groups.Friend;
import edu.tsinghua.lumaqq.xml.groups.Group;
import edu.tsinghua.lumaqq.xml.groups.Groups;
import edu.tsinghua.lumaqq.xml.groups.GroupsImpl;
import edu.tsinghua.lumaqq.xml.groups.GroupsUnmarshaller;
import edu.tsinghua.lumaqq.xml.proxies.Proxies;
import edu.tsinghua.lumaqq.xml.proxies.ProxiesUnmarshaller;
import edu.tsinghua.lumaqq.xml.remarks.Remark;
import edu.tsinghua.lumaqq.xml.remarks.Remarks;
import edu.tsinghua.lumaqq.xml.remarks.RemarksUnmarshaller;
import edu.tsinghua.lumaqq.xml.replies.Replies;
import edu.tsinghua.lumaqq.xml.replies.RepliesUnmarshaller;
import edu.tsinghua.lumaqq.xml.sysopts.Options;
import edu.tsinghua.lumaqq.xml.sysopts.OptionsUnmarshaller;
import edu.tsinghua.swt.events.GeneralModelEvent;
import edu.tsinghua.swt.events.PropertyEvent;
import edu.tsinghua.swt.events.PropertyListener;
import edu.tsinghua.swt.events.ShutterLabelEvent;
import edu.tsinghua.swt.events.ShutterLabelListener;
import edu.tsinghua.swt.events.ShutterModelEvent;
import edu.tsinghua.swt.events.ShutterModelListener;
import edu.tsinghua.swt.models.DefaultShutterModel;
import edu.tsinghua.swt.models.INode;
import edu.tsinghua.swt.models.ShutterModel;
import edu.tsinghua.swt.widgets.MySWT;
import edu.tsinghua.swt.widgets.Shutter;
import edu.tsinghua.swt.widgets.ShutterLabel;
/**
* 主界面
*
* @author 马若劼
*/
public class MainShell extends ShellAdapter implements DisposeListener, ShutterModelListener, PropertyListener, QQListener, ControlListener, QQShowListener {
// 当用户选择好友菜单中的改名时,此监听器将被暂时添加到好友上
private class FriendShutterLabelListener implements ShutterLabelListener {
public void textChanged(ShutterLabelEvent e) {
ShutterLabel label = (ShutterLabel)e.getSource();
if(e.newText.equals("")) // 如果新文本为空,不做出修改
label.setText(e.oldText);
else {
FriendModel f = (FriendModel)label.getData();
f.addProperty("realName", e.newText);
if(options.isShowNick()) {
displayName("realName");
options.setShowNick(false);
} else
f.addProperty("name", e.newText);
}
label.removeShutterLabelListener(fsll);
}
}
// 当用户在黑名单中添加一个坏人时,这个listener监听text changed事件,也就是用户输入完
// 坏人的QQ号后这个listener被调用,主要作用就是得到用户输入的QQ号,然后把这个QQ号
// 从好友中删除(如果有的话,然后再把自己从这个QQ号的好友列表中删除
private class BlackListShutterLabelListener implements ShutterLabelListener {
public void textChanged(ShutterLabelEvent e) {
ShutterLabel label = (ShutterLabel)e.getSource();
FriendModel f = (FriendModel)label.getData();
Integer qq = Utils.getInteger(e.newText, null);
if(qq == null) {
// 用户输入的QQ号有误,删除这个item
int[] blacklist = model.findTabIndex(blacklistMatcher);
int index = model.indexOfItem(blacklist[0], f);
model.removeItem(blacklist[0], index);
label.removeShutterLabelListener(blsll);
return;
}
// 得到这个好友的viewPart,这一步放在前面做,如果放在后面
// 因为f将要添加qq属性,所以就肯定会找到了
ShutterLabel viewPart = getFriendViewPart(qq.intValue());
// 添加属性
f.addProperty("qq", qq);
f.addProperty("member", "false");
f.addProperty("name", e.newText);
f.addProperty("nick", e.newText);
f.addProperty("contact", ModelUtils.createContact(f));
label.removeShutterLabelListener(blsll);
// 开始删除
if(viewPart != null)
deleteFriend(viewPart, false, true);
else
deleteFriendFromServer(qq.intValue(), false, true, null);
}
}
// 闪烁图标
private class Blink implements Runnable {
private Image blinkImage;
private boolean flag;
private volatile boolean stop;
public Blink() {
stop = true;
}
public void setBlinkImage(Image blinkImage) {
this.blinkImage = blinkImage;
this.flag = true;
this.stop = false;
}
public void run() {
try {
if(flag)
item.setImage(blinkImage);
else
item.setImage(icons.getResource(IconHolder.icoBlank));
flag = !flag;
if(!stop)
display.timerExec(500, this);
else
setIconByStatus();
} catch (SWTException e) {
// 这个操作可能会抛出SWTException,如果组件已经dispose的话,
// 所以我们需要捕捉这个异常,不然程序可能崩溃
}
}
public void setStop(boolean stop) {
this.stop = stop;
}
public boolean isStop() {
return stop;
}
}
public Shell shell;
public Display display;
protected TrayItem item;
public Shutter shutter;
protected ShutterLabel btnStatus, btnSysMsg, btnSysMenu;
protected QQClient client;
public IconHolder icons = IconHolder.getInstance();
// Log对象
private static Log log = LogFactory.getLog(MainShell.class);
// 分组信息文件根元素对象
private Groups groups;
// Shutter Model
public ShutterModel model;
// 两个弹出菜单
public Menu statusMenu, sysMenu, groupMenu, friendMenu, awayMenu, displayMenu, clusterMenu;
// 保存Shell的位置,windows不需要,linux下需要
private Point loc;
// 是否在闪烁一个图标
private boolean blinking;
// 是否从服务器请求好友列表
protected boolean getFriendFromServer;
// 登陆动画帧
protected Image[] loginFrames;
// QQ事件处理器
private QQEventProcessor processor;
// 消息队列
protected MessageQueue mq;
// QQ号码比较器
protected QQNumberMatcher qqNumMatcher;
// 黑名单组查找器
protected BlacklistMatcher blacklistMatcher;
// 陌生人组查找器
protected StrangerMatcher strangerMatcher;
// 好友组查找器
protected FriendlyMatcher friendlyMatcher;
// 群组查找器
protected ClusterMatcher clusterMatcher;
// 群查找器
protected ClusterIdMatcher clusterIdMatcher;
// 闪烁Runnable
private Blink blinkRunnable;
// 存放当前已经打开的查看消息窗口
private Hashtable rmsMap;
// 存放当前已经打开的发送消息窗口
private Hashtable smsMap;
// 存放当前已经打开的用户资料查看窗口
private Hashtable uisMap;
// 存放当前已经打开的群资料查看窗口
private Hashtable cisMap;
// 存放当前已经打开的群消息发送窗口
private Hashtable scmsMap;
// 删除请求哈希表,这个哈希表说明了如果某个用户删除成功就要把这个用户弄到哪个组去
private Hashtable deleteToMap;
// 用户自己的model
protected FriendModel myModel;
// item鼠标事件监听器,item可能是群,也可能是好友
private ItemMouseListener itemMouseListener;
private ItemMouseTrackListener itemMouseTrackListener;
// 组鼠标事件监听器
private GroupMouseListener groupMouseListener;
// 黑名单是否可见
private boolean blacklistVisible;
// 当前在线人数
protected String currentOnlineNumber;
// 好友列表是否已经得到
protected boolean friendListFinished;
// 搜索用户窗口,为null表示没有打开
protected SearchShell searchShell;
// 创建群窗口,为null表示没有打开
protected CreateClusterShell createClusterShell;
// 系统设置窗口,为null表示没有打开
protected SystemOptionShell systemOptionShell;
// 系统消息列表对话框,为null表示没有打开
protected SystemMessageListDialog systemMessageListDialog;
// 当前消息字体和颜色,null为缺省
protected Font font;
protected Color fontColor;
// ip查找类引用
protected IPSeeker seeker;
// 上传下载分组提示对话框,用来表示目前正在进行操作,也用来判断是否目前有上传下载操作在
// 进行,如果这个不为null,表示目前正有上传下载操作在进行,将不允许再有其他上传下载
// 操作同时进行
protected OperationShell opDialog;
// 黑名单组shutter label 文字改变事件监听器
private BlackListShutterLabelListener blsll;
// 好友改名时的shutter label文字改变事件监听器
private FriendShutterLabelListener fsll;
// 声音播放精灵线程
protected SoundDaemon soundDaemon;
// 参数工具类实例
protected OptionUtils options = OptionUtils.getInstance();
// 回复信息工具类实例
private ReplyUtils replies = ReplyUtils.getInstance();
// 备注信息工具类实例
private RemarkUtils remarks = RemarkUtils.getInstance();
// 代理列表工具类实例
private ProxyUtils proxies = ProxyUtils.getInstance();
// 当前在线好友
protected List currentOnlines;
// 好友添加的哈希表,这个哈希表保存了要把好友添加到的目的组
protected Hashtable addTos;
// 聊天记录管理器
protected IMessage mm;
// QQ秀管理器
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -