📄 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.ui;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
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.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
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.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import edu.tsinghua.lumaqq.Colors;
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.MessageQueue;
import edu.tsinghua.lumaqq.ModelUtils;
import edu.tsinghua.lumaqq.QQShowManager;
import edu.tsinghua.lumaqq.SoundDaemon;
import edu.tsinghua.lumaqq.events.FriendDragSourceListener;
import edu.tsinghua.lumaqq.events.FriendPropertyListener;
import edu.tsinghua.lumaqq.events.GroupDropTargetListener;
import edu.tsinghua.lumaqq.events.GroupPropertyListener;
import edu.tsinghua.lumaqq.events.LumaQQModelListener;
import edu.tsinghua.lumaqq.events.MobileMouseListener;
import edu.tsinghua.lumaqq.events.QQShowEvent;
import edu.tsinghua.lumaqq.events.IQQShowListener;
import edu.tsinghua.lumaqq.models.FriendModel;
import edu.tsinghua.lumaqq.models.GroupModel;
import edu.tsinghua.lumaqq.models.IQQNode;
import edu.tsinghua.lumaqq.models.MobileModelSorter;
import edu.tsinghua.lumaqq.models.ModelSorter;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.QQClient;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.ui.config.user.UserInfoWindow;
import edu.tsinghua.lumaqq.ui.dialogs.LoginDialog;
import edu.tsinghua.lumaqq.ui.helper.ConfigHelper;
import edu.tsinghua.lumaqq.ui.helper.ExportHelper;
import edu.tsinghua.lumaqq.ui.helper.MVCHelper;
import edu.tsinghua.lumaqq.ui.helper.MenuHelper;
import edu.tsinghua.lumaqq.ui.helper.MessageHelper;
import edu.tsinghua.lumaqq.ui.helper.TipHelper;
import edu.tsinghua.lumaqq.ui.helper.UIHelper;
import edu.tsinghua.lumaqq.ui.jobs.JobExecutor;
import edu.tsinghua.lumaqq.ui.jobs.UploadGroupJob;
import edu.tsinghua.lumaqq.ui.tool.ShellLauncher;
import edu.tsinghua.lumaqq.ui.tool.ShellRegistry;
import edu.tsinghua.lumaqq.utils.MobileUtil;
import edu.tsinghua.lumaqq.utils.OptionUtil;
import edu.tsinghua.lumaqq.utils.ProxyUtil;
import edu.tsinghua.lumaqq.utils.RemarkUtil;
import edu.tsinghua.lumaqq.utils.ReplyUtil;
import edu.tsinghua.lumaqq.widgets.rich.LineStyle;
import edu.tsinghua.lumaqq.xml.remarks.Remark;
import edu.tsinghua.lumaqq.xml.remarks.RemarkImpl;
import edu.tsinghua.swt.events.CoolButtonEvent;
import edu.tsinghua.swt.events.CoolButtonListener;
import edu.tsinghua.swt.events.ModelEvent;
import edu.tsinghua.swt.events.PropertyEvent;
import edu.tsinghua.swt.events.PropertyListener;
import edu.tsinghua.swt.events.ShutterModelEvent;
import edu.tsinghua.swt.events.ShutterModelListener;
import edu.tsinghua.swt.models.INode;
import edu.tsinghua.swt.models.ShutterModel;
import edu.tsinghua.swt.widgets.CoolButton;
import edu.tsinghua.swt.widgets.MySWT;
import edu.tsinghua.swt.widgets.Shutter;
/**
* 主界面
*
* @author 马若劼
*/
public class MainShell extends ShellAdapter implements DisposeListener, ShutterModelListener, PropertyListener, ControlListener, IQQShowListener {
/**
* <pre>
* 当用户选择好友菜单中的改名时,此监听器将被暂时添加到好友上
* </pre>
*
* @author 马若劼
*/
private class FriendCoolButtonListener implements CoolButtonListener {
/**
* @see edu.tsinghua.swt.events.CoolButtonListener#textChanged(edu.tsinghua.swt.events.CoolButtonEvent)
*/
public void textChanged(CoolButtonEvent e) {
CoolButton label = (CoolButton)e.getSource();
if(e.newText.equals("")) // 如果新文本为空,不做出修改
label.setText(e.oldText);
else {
FriendModel f = (FriendModel)label.getData();
setFriendProperty(f, IQQNode.REAL_NAME, e.newText);
if(options.isShowNick()) {
uiHelper.displayName(IQQNode.REAL_NAME);
options.setShowNick(false);
} else
setFriendProperty(f, INode.NAME, e.newText);
// 创建备注对象,保存
Remark remark = remarks.getRemark(f.getQQ());
if(remark == null) {
remark = new RemarkImpl();
remark.setQqNum(String.valueOf(f.getQQ()));
}
remark.setName(e.newText);
remarks.addRemark(remark);
remarks.save();
}
label.removeShutterLabelListener(fsll);
}
}
/**
* <pre>
* 当用户在黑名单中添加一个坏人时,这个listener监听text changed事件,也就是用户输入完
* 坏人的QQ号后这个listener被调用,主要作用就是得到用户输入的QQ号,然后把这个QQ号
* 从好友中删除(如果有的话,然后再把自己从这个QQ号的好友列表中删除
* </pre>
*
* @author 马若劼
*/
private class BlackListCoolButtonListener implements CoolButtonListener {
public void textChanged(CoolButtonEvent e) {
CoolButton label = (CoolButton)e.getSource();
FriendModel f = (FriendModel)label.getData();
Integer qq = Util.getInteger(e.newText, null);
if(qq == null) {
// 用户输入的QQ号有误,删除这个item
int[] blacklist = mvcHelper.listBlacklistGroup();
int index = model.indexOfItem(blacklist[0], f);
model.removeItem(blacklist[0], index);
label.removeShutterLabelListener(blsll);
return;
}
// 得到这个好友的viewPart,这一步放在前面做,如果放在后面
// 因为f将要添加qq属性,所以就肯定会找到了
CoolButton viewPart = mvcHelper.getFriendViewPart(qq.intValue());
// 添加属性
f.addProperty(IQQNode.QQ_NUMBER, qq);
f.addProperty(IQQNode.MEMBER, "false");
f.addProperty(INode.NAME, e.newText);
f.addProperty(IQQNode.NICK, e.newText);
f.addProperty(IQQNode.CONTACT, ModelUtils.createContact(f));
label.removeShutterLabelListener(blsll);
// 开始删除
if(viewPart != null)
deleteFriend(viewPart, false, true);
else
deleteFriendFromServer(qq.intValue(), false, true, null);
}
}
private Shell shell;
private Display display;
private TrayItem item;
private Shutter shutter;
private CoolButton btnStatus, btnSysMsg, btnSysMenu, btnSMS;
private QQClient client;
private IconHolder icons;
// Log对象
private static Log log = LogFactory.getLog(MainShell.class);
// Shutter Model
private ShutterModel model;
// 手机好友model
private ShutterModel mobileModel;
// 保存Shell的位置,windows不需要,linux下需要
private Point loc;
// 是否在闪烁一个图标
private boolean blinking;
// 分组信息是否已经被修改
private boolean groupDirty;
// 登陆动画帧
private Image[] loginFrames;
// QQ事件处理器
private QQEventProcessor processor;
// 群贴图接收器
private ClusterCustomFaceReceiver faceReceiver;
// 消息队列
private MessageQueue mq;
// 删除请求哈希表,这个哈希表说明了如果某个用户删除成功就要把这个用户弄到哪个组去
private Hashtable deleteToMap;
// 窗口注册表
private ShellRegistry shellRegistry;
// 窗口发射器
private ShellLauncher shellLauncher;
// MVC帮助类
private MVCHelper mvcHelper;
// UI帮助类
private UIHelper uiHelper;
// 导出帮助类
private ExportHelper exportHelper;
// 消息处理帮助类
private MessageHelper messageHelper;
// 配置文件帮助类
private ConfigHelper configHelper;
// 菜单帮助类
private MenuHelper menuHelper;
// 提示窗口帮助类
private TipHelper tipHelper;
// 用户自己的model
private FriendModel myModel;
// 黑名单是否可见
private boolean blacklistVisible;
// 当前在线人数的字符串表示
private String currentOnlineNumber;
// 好友列表是否已经得到
private boolean friendListFinished;
// 当前消息字体和颜色,null为缺省
private Font font;
private LineStyle defaultStyle;
// 组背景颜色,如果为null,为缺省颜色
private Color groupColor;
// shutter的边框色
private Color shutterBorderColor;
// ip查找类引用
private IPSeeker seeker;
// 黑名单组shutter label 文字改变事件监听器
private BlackListCoolButtonListener blsll;
// 好友改名时的shutter label文字改变事件监听器
private FriendCoolButtonListener fsll;
// 声音播放精灵线程
private SoundDaemon soundDaemon;
// 参数工具类实例
private OptionUtil options = OptionUtil.getInstance();
// 回复信息工具类实例
private ReplyUtil replies = ReplyUtil.getInstance();
// 备注信息工具类实例
private RemarkUtil remarks = RemarkUtil.getInstance();
// 代理列表工具类实例
private ProxyUtil proxies = ProxyUtil.getInstance();
// 手机好友列表工具类
private MobileUtil mobiles = MobileUtil.getInstance();
// 当前在线好友
private List currentOnlines;
// 聊天记录管理器
private IMessage mm;
// QQ秀管理器
private QQShowManager sm;
// view bar
private Composite viewBar;
// 自动隐藏管理器,在windows下面已经没有问题,linux还是搞不定,注释掉先
//protected AutoHideManager ahm;
// 切换view的tab按钮数组
private CoolButton[] viewButtons;
private static final int VIEW_COUNT = 2;
private static final int FRIEND_VIEW = 0;
private static final int MOBILE_VIEW = 1;
// shutter数组,每个shutter代表了一个view
private Shutter[] views;
// 当前view
private int currentView;
/**
* 构造函数
*/
public MainShell() {
this.display = new Display();
shell = new Shell(display, SWT.CLOSE | SWT.MIN | SWT.RESIZE);
icons = IconHolder.getInstance();
shell.setImage(icons.getImage(IconHolder.icoQQ));
// 添加事件监听器
shell.addDisposeListener(this);
shell.addShellListener(this);
shell.addControlListener(this);
display.addFilter(SWT.KeyDown, new Listener() {
public void handleEvent(Event e) {
if(e.keyCode == 'z' && (e.stateMask & SWT.CTRL) != 0 && (e.stateMask & SWT.ALT) != 0) {
if(mq.hasNext()) {
int source = mq.nextMessageSource();
if(source == QQ.QQ_IM_FROM_SYS)
shellLauncher.openReceiveSystemMessageShell(mq.getSystemMessage());
else if(source == QQ.QQ_IM_FROM_SMS)
shellLauncher.openReceiveSMSShell();
else {
int sender = mq.nextSender();
shellLauncher.openIMShell(sender);
}
} else {
menuHelper.setStatusMenuVisible(false);
shell.setLocation(loc);
shell.setMinimized(false);
shell.setVisible(true);
}
}
}
});
// 初始化变量
loginFrames = new Image[] {
icons.getImage(IconHolder.icoOffline),
icons.getImage(IconHolder.icoAway),
icons.getImage(IconHolder.icoHidden),
icons.getImage(IconHolder.icoOnline)
};
Colors.init();
mq = MessageQueue.getInstance();
seeker = IPSeeker.getInstance();
processor = new QQEventProcessor(this);
faceReceiver = new ClusterCustomFaceReceiver(this);
deleteToMap = new Hashtable();
shellRegistry = new ShellRegistry();
shellLauncher = new ShellLauncher(this);
mvcHelper = new MVCHelper(this);
uiHelper = new UIHelper(this);
exportHelper = new ExportHelper(this);
messageHelper = new MessageHelper(this);
configHelper = new ConfigHelper(this);
tipHelper = new TipHelper(this);
currentOnlineNumber = LumaQQ.getString("search.current.online.unknown");
blsll = new BlackListCoolButtonListener();
fsll = new FriendCoolButtonListener();
soundDaemon = new SoundDaemon();
currentOnlines = new ArrayList();
shutterBorderColor = new Color(display, 0x29, 0x5D, 0xA5);
viewButtons = new CoolButton[VIEW_COUNT];
views = new Shutter[VIEW_COUNT];
// 初始化组件
initLayout();
// 初始化菜单
menuHelper = new MenuHelper(this);
menuHelper.initMenu();
// 监听主窗口未知,负责自动隐藏
//ahm = new AutoHideManager(this);
}
/**
* 改变当前用户
*/
public void changeUser() {
LoginDialog login = new LoginDialog(shell);
if(login.open()) {
int qqNum = login.getQQ();
if(myModel.getQQ() != qqNum) {
client.logout();
uiHelper.setIconByStatus();
// 创建QQ用户对象
QQUser me = new QQUser(qqNum, login.getMd5Password());
if(login.isLoginHidden()) {
me.setLoginMode(QQ.QQ_LOGIN_MODE_HIDDEN);
me.setStatus(QQ.QQ_FRIEND_STATUS_HIDDEN);
} else {
me.setLoginMode(QQ.QQ_LOGIN_MODE_NORMAL);
me.setStatus(QQ.QQ_FRIEND_STATUS_ONLINE);
}
// 创建QQ客户端对象
client.setUser(me);
// 初始化用户文件路径
LumaQQ.initUserFilePath(me);
// 设置client
setClient(this.client);
// 设置tray的tooltip
item.setToolTipText("LumaQQ " + String.valueOf(client.getUser().getQQ()));
// shutter控件重新layout
shutter.layout();
// 登陆
checkLogin(false, false);
}
}
}
/**
* 使自己处于下线状态
*/
public void logout() {
// 注销
client.logout();
// 停止所有动画
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -