📄 searchshell.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.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
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.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.Image;
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.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import edu.tsinghua.lumaqq.IconHolder;
import edu.tsinghua.lumaqq.LumaQQ;
import edu.tsinghua.lumaqq.models.ClusterModel;
import edu.tsinghua.lumaqq.models.FriendModel;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.Utils;
import edu.tsinghua.lumaqq.qq.beans.ClusterInfo;
import edu.tsinghua.lumaqq.qq.beans.OnlineUser;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.events.QQListener;
import edu.tsinghua.lumaqq.qq.packets.in.ClusterCommandReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SearchUserReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.AddFriendPacket;
import edu.tsinghua.lumaqq.qq.packets.out.ClusterCommandPacket;
import edu.tsinghua.swt.widgets.MySWT;
import edu.tsinghua.swt.widgets.ShutterLabel;
/**
* 搜索用户的对话框。对于一次搜索,总会到达最后一页的,但是似乎如果是自定义搜索,而且
* 指定了QQ号,也就是说你只想搜索一个特定的用户,这个时候服务器似乎有bug,不会返回结束
* 标志,总是能搜到这个用户,页数也不停的长,但是其他情况的自定义搜索就不会,这也许是
* TX服务器的bug吧
*
* @author 马若劼
*/
public class SearchShell extends ShellAdapter implements QQListener {
// 相应搜索用户结果表中的表头点击事件,动作是把表的内容排序
private class TableColumnListener extends SelectionAdapter {
// 列排序器
private Comparator comparator;
public TableColumnListener(Comparator comparator) {
this.comparator = comparator;
}
public void widgetSelected(SelectionEvent e) {
// 上次是升序这次就降序,上次降序这次就升序
ascending = -ascending;
// 对OnlineUser列表排序
List list = null;
if(showAll) {
list = new ArrayList();
int size = pages.size();
for(int i = 1; i <= size; i++)
list.addAll((Collection)pages.get(new Integer(i)));
} else {
list = (List)pages.get(new Integer(page));
}
if(list != null) {
Collections.sort(list, comparator);
userTable.removeAll();
parseUserList(list);
}
}
}
// 比较OnlineUser中的昵称
private class NickComparator implements Comparator {
public int compare(Object o1, Object o2) {
OnlineUser u1 = (OnlineUser)o1;
OnlineUser u2 = (OnlineUser)o2;
String n1 = null, n2 = null;
String _n1 = u1.nick.trim();
String _n2 = u2.nick.trim();
try {
n1 = new String(_n1.getBytes("GBK"), "ISO-8859-1");
n2 = new String(_n2.getBytes("GBK"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
n1 = _n1;
n2 = _n2;
}
return n1.compareTo(n2) * ascending;
}
}
// 比较OnlineUser中的省份
private class ProvinceComparator implements Comparator {
public int compare(Object o1, Object o2) {
OnlineUser u1 = (OnlineUser)o1;
OnlineUser u2 = (OnlineUser)o2;
String n1 = null, n2 = null;
String _n1 = u1.province.trim();
String _n2 = u2.province.trim();
try {
n1 = new String(_n1.getBytes("GBK"), "ISO-8859-1");
n2 = new String(_n2.getBytes("GBK"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
n1 = _n1;
n2 = _n2;
}
return n1.compareTo(n2) * ascending;
}
}
// 比较OnlineUser中的QQ号
private class QQNumComparator implements Comparator {
public int compare(Object o1, Object o2) {
OnlineUser u1 = (OnlineUser)o1;
OnlineUser u2 = (OnlineUser)o2;
if(u1.qqNum == u2.qqNum)
return 0;
else
return ((u1.qqNum > u2.qqNum) ? 1 : -1) * ascending;
}
}
public static final int ALL = 0;
public static final int CUSTOM = 1;
public static final int POWER = 2;
public static final int CLUSTER = 3;
// Log对象
protected static Log log = LogFactory.getLog(SearchShell.class);
private MainShell main;
private Shell shell;
private Display display;
private Label lblLogo, lblSeparator, lblOnline, lblPage, lblNick, lblPlace, lblHint, lblId, lblClusterHint;
private ShutterLabel btnNext, btnPrevious, btnFace, btnAll, btnPreviousPage, btnNextPage, btnDetail, btnClusterDetail;
private Composite first, list, add, custom, power, cluster, clusterList;
private Table userTable, clusterTable;
private Text textAuth, textQQ, textNick, textEmail, textId;
private Button btnSend, chkEntire, radioById, radioDemo;
private Group waitGroup;
private IconHolder icons = IconHolder.getInstance();
// 搜索方式
private int mode;
// 目前步数
private int step;
// 当前用户列表页数,代表当前显示的页号,从1开始
private int page;
// 上一个显示的面板
private Composite prevPanel;
// 保存已经搜到的用户的哈希表
private Hashtable pages;
// 当前选择要添加的用户的QQ号
private int qqNum;
// 当前选择要添加的群的内部ID
private int clusterId;
// 动画帧数组
private Image[] frames;
// 当前排序状态,升序还是降序,1表示升序,-1表示降序
private int ascending;
// 当前是否是显示全部搜到的用户
private boolean showAll;
/**
* 构造函数
* @param main MainShell对象
*/
public SearchShell(MainShell main) {
this.main = main;
this.display = main.display;
shell = new Shell(display, SWT.TITLE | SWT.CLOSE | SWT.MIN);
shell.setSize(450, 320);
shell.setImage(icons.getResource(IconHolder.icoFind));
shell.setText(LumaQQ.getResourceString("search.title"));
// 设置layout
shell.setLayout(new FormLayout());
// 添加事件监听器
shell.addShellListener(this);
// 初始化变量
mode = ALL;
step = 1;
page = 0;
pages = new Hashtable();
ascending = -1;
showAll = false;
initLayout();
}
// 初始化其他控件
private void initLayout() {
// 旁边的logo
lblLogo = new Label(shell, SWT.NONE);
lblLogo.setImage(icons.getResource(IconHolder.bmpSearch));
FormData fd = new FormData();
fd.left = fd.top = new FormAttachment(0, 15);
fd.right = new FormAttachment(0, lblLogo.getImage().getBounds().width + 15);
fd.bottom = new FormAttachment(0, lblLogo.getImage().getBounds().height + 15);
lblLogo.setLayoutData(fd);
// 最下面的水平separator
lblSeparator = new Label(shell, SWT.HORIZONTAL | SWT.SEPARATOR);
fd = new FormData();
fd.left = new FormAttachment(0, 10);
fd.top = new FormAttachment(100, -40);
fd.right = new FormAttachment(100, -10);
lblSeparator.setLayoutData(fd);
// 取消按钮
ShutterLabel btnCancel = new ShutterLabel(shell, MySWT.HOVER | SWT.CENTER, LumaQQ.getResourceString("search.button.cancel"), null);
fd = new FormData();
fd.left = new FormAttachment(100, -90);
fd.right = new FormAttachment(100, -10);
fd.top = new FormAttachment(100, -28);
btnCancel.setLayoutData(fd);
btnCancel.addMouseListener(
new MouseAdapter() {
public void mouseUp(MouseEvent e) {
close();
}
}
);
// 下一步按钮
btnNext = new ShutterLabel(shell, MySWT.HOVER | SWT.CENTER, LumaQQ.getResourceString("search.button.next"), null);
fd = new FormData();
fd.left = new FormAttachment(btnCancel, -90, SWT.LEFT);
fd.right = new FormAttachment(btnCancel, -10, SWT.LEFT);
fd.top = new FormAttachment(100, -28);
btnNext.setLayoutData(fd);
btnNext.addMouseListener(
new MouseAdapter() {
public void mouseUp(MouseEvent e) {
navigateNext();
}
}
);
// 上一步按钮
btnPrevious = new ShutterLabel(shell, MySWT.HOVER | SWT.CENTER, LumaQQ.getResourceString("search.button.previous"), null);
btnPrevious.setEnabled(false);
fd = new FormData();
fd.left = new FormAttachment(btnNext, -80, SWT.LEFT);
fd.right = new FormAttachment(btnNext, 0, SWT.LEFT);
fd.top = new FormAttachment(100, -28);
btnPrevious.setLayoutData(fd);
btnPrevious.addMouseListener(
new MouseAdapter() {
public void mouseUp(MouseEvent e) {
navigatePrevious();
}
}
);
// 初始化搜索首页面板,用户在这里选择哪种搜索类型
initFirstPanel();
// 初始化用户列表面板,用户在这里查看搜索到的用户
initListPanel();
// 初始化添加好友面板,用户在这里等待服务器的应答
initAddPanel();
// 初始化自定义搜索参数输入面板,用户在这里填写自定义搜索参数
initCustomPanel();
// 初始化强力搜索面板,用户在这里填写高级搜索参数
//initPowerPanel();
// 初始化群搜索方式选择面板
initClusterPanel();
// 初始化群列表面板
initClusterListPanel();
}
// 初始化群列表面板
private void initClusterListPanel() {
clusterList = createPanel();
clusterList.setVisible(false);
// 提示标签
lblClusterHint = new Label(clusterList, SWT.HORIZONTAL | SWT.WRAP);
FormData fd = new FormData();
fd.left = new FormAttachment(0, 0);
fd.right = new FormAttachment(100, 0);
fd.bottom = new FormAttachment(100, 0);
lblClusterHint.setLayoutData(fd);
// 详细资料按钮
btnClusterDetail = new ShutterLabel(clusterList, MySWT.HOVER | SWT.CENTER, LumaQQ.getResourceString("search.button.detail"), null);
fd = new FormData();
fd.bottom = new FormAttachment(lblClusterHint, -3, SWT.TOP);
fd.right = new FormAttachment(100, 0);
btnClusterDetail.setLayoutData(fd);
btnClusterDetail.addMouseListener(
new MouseAdapter() {
public void mouseUp(MouseEvent e) {
int index = clusterTable.getSelectionIndex();
if(index == -1)
openMessageBox(LumaQQ.getResourceString("message.box.please.select.cluster"));
else {
TableItem ti = clusterTable.getItem(index);
ClusterInfo info = (ClusterInfo)ti.getData();
ClusterModel c = new ClusterModel(info.clusterId, info.name);
c.addProperty("info", info);
main.openClusterInfoShell(c).showBasicOnly();
}
}
}
);
// table控件
clusterTable = new Table(clusterList, SWT.SINGLE | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
clusterTable.setHeaderVisible(true);
fd = new FormData();
fd.left = fd.top = new FormAttachment(0, 0);
fd.right = new FormAttachment(100, 0);
fd.bottom = new FormAttachment(btnClusterDetail, -3, SWT.TOP);
clusterTable.setLayoutData(fd);
// 表的header, 1. 群组号码, 2.群组名称, 3.群组创建者
TableColumn tc = new TableColumn(clusterTable, SWT.LEFT);
tc.setText(LumaQQ.getResourceString("search.table.column.id"));
tc.setWidth(80);
tc = new TableColumn(clusterTable, SWT.CENTER);
tc.setText(LumaQQ.getResourceString("search.table.column.name"));
tc.setWidth(120);
tc = new TableColumn(clusterTable, SWT.CENTER);
tc.setText(LumaQQ.getResourceString("search.table.column.creator"));
tc.setWidth(80);
}
// 初始化群搜索方式选择面板
private void initClusterPanel() {
cluster = createPanel();
cluster.setVisible(false);
// 提示标签
Label lblHint = new Label(cluster, SWT.WRAP);
lblHint.setText(LumaQQ.getResourceString("search.label.cluster.hint"));
FormData fd = new FormData();
fd.left = fd.top = new FormAttachment(0, 0);
fd.right = new FormAttachment(100, 0);
fd.bottom = new FormAttachment(30, 0);
lblHint.setLayoutData(fd);
// 搜索方式组
Group group = new Group(cluster, SWT.SHADOW_ETCHED_OUT);
group.setText(LumaQQ.getResourceString("search.group.select"));
fd = new FormData();
fd.left = new FormAttachment(0, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -