📄 smswindow.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 static edu.tsinghua.lumaqq.resource.Messages.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellEvent;
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.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import edu.tsinghua.lumaqq.events.FriendSelectionEvent;
import edu.tsinghua.lumaqq.events.IFriendSelectionListener;
import edu.tsinghua.lumaqq.models.Model;
import edu.tsinghua.lumaqq.models.ModelRegistry;
import edu.tsinghua.lumaqq.models.User;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.beans.SMSReply;
import edu.tsinghua.lumaqq.qq.events.IQQListener;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.packets.in.ReceiveIMPacket;
import edu.tsinghua.lumaqq.qq.packets.in.SendSMSReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.out.SendSMSPacket;
import edu.tsinghua.lumaqq.record.IKeyConstants;
import edu.tsinghua.lumaqq.record.RecordEntry;
import edu.tsinghua.lumaqq.resource.Colors;
import edu.tsinghua.lumaqq.resource.DefaultFace;
import edu.tsinghua.lumaqq.resource.Resources;
import edu.tsinghua.lumaqq.ui.helper.DateTool;
import edu.tsinghua.lumaqq.ui.helper.UITool;
import edu.tsinghua.lumaqq.ui.listener.CenterBorderPaintListener;
import edu.tsinghua.lumaqq.widgets.qstyle.Slat;
import edu.tsinghua.lumaqq.widgets.record.RecordViewer;
import edu.tsinghua.lumaqq.widgets.record.SMSFilter;
import edu.tsinghua.lumaqq.widgets.record.SMSRecordProvider;
import edu.tsinghua.lumaqq.widgets.rich.LineStyle;
import edu.tsinghua.lumaqq.widgets.rich.RichBox;
/**
* 短信发送接收窗口
*
* @author luma
*/
public class SMSWindow extends BaseWindow implements IQQListener, IFriendSelectionListener {
/**
* 闪烁图标
*
* @author luma
*/
private class Blink implements Runnable {
private boolean flag;
private volatile boolean stop;
public Blink() {
stop = true;
}
public void init() {
this.flag = true;
this.stop = false;
}
public void run() {
try {
if (flag) {
getShell().setImage(res.getImage(Resources.icoMobile));
((BorderStyler) getShell().getData(BorderStyler.STYLER)).repaintTitleBar();
} else {
getShell().setImage(null);
((BorderStyler) getShell().getData(BorderStyler.STYLER)).repaintTitleBar();
}
flag = !flag;
if (!stop)
getShell().getDisplay().timerExec(500, this);
else {
getShell().setImage(res.getImage(Resources.icoMobile));
((BorderStyler) getShell().getData(BorderStyler.STYLER)).repaintTitleBar();
}
} catch (SWTException e) {
// 这个操作可能会抛出SWTException,如果组件已经dispose的话,
// 所以我们需要捕捉这个异常,不然程序可能崩溃
}
}
public void setStop(boolean stop) {
this.stop = stop;
}
public boolean isStop() {
return stop;
}
}
private FriendSelectionShell fss;
private String receiver;
private RichBox inputBox;
private Text textSender;
private RecordViewer viewer;
// true表示窗口处于一对一发送接收模式,这种模式下不能选择收件人,需要预设,可以发送和接收
// false表示窗口处于可以多人发送模式,这种模式下可以选择1到多个收件人,只能发送
private boolean singleMode;
private boolean isUser;
private User friend;
private String mobile;
// 消息要发送到的手机和好友QQ号列表
private List<String> mobiles;
private List<Integer> friends;
// 短信的分片相关
private int fragmentCount;
private int nextFragment;
private int maxFragmentLength;
private byte[] fragmentCache;
// 要发送的消息
private String textCache;
// 是否停止发送
private boolean stop;
// 当前是否有发送在进行中
private boolean sending;
private char expected;
private Blink blink;
private static final LineStyle myStyle = new LineStyle(Colors.MY_HINT_COLOR, null, "宋体", SWT.NORMAL, 9);
private static final LineStyle otherStyle = new LineStyle(Colors.BLUE, null, "宋体", SWT.NORMAL, 9);
private static final String CRLF = System.getProperty("line.separator");
private Runnable sendAction = new Runnable() {
public void run() {
textCache = inputBox.getText();
send();
}
};
private Runnable recordAction = new Runnable() {
public void run() {
showRecord();
}
};
private RichBox outputBox;
private Slat btnSend;
private Text textReceiver;
private Label lblHint;
public SMSWindow(MainShell main, String mobile) {
super(main);
this.mobile = mobile;
isUser = false;
singleMode = true;
}
public SMSWindow(MainShell main, User friend) {
super(main);
this.friend = friend;
isUser = true;
singleMode = true;
}
public SMSWindow(MainShell main) {
super(main);
singleMode = false;
}
@Override
protected void initializeVariables() {
super.initializeVariables();
mobiles = new ArrayList<String>();
friends = new ArrayList<Integer>();
maxFragmentLength = QQ.QQ_MAX_SMS_LENGTH - QQ.QQ_MAX_SMS_SENDER_NAME;
fragmentCount = 1;
nextFragment = 0;
stop = true;
sending = false;
blink = new Blink();
receiver = "";
expected = 0;
}
/**
* 开始闪烁系统消息图标
*/
public void startBlink() {
if (!blink.isStop())
return;
blink.init();
getShell().getDisplay().timerExec(0, blink);
}
/**
* 停止系统消息按钮上的闪烁效果
*/
public void stopBlink() {
blink.setStop(true);
}
@Override
protected String getTitle() {
User me = main.getMyModel();
if (me.isMobile())
return NLS.bind(sms_title_mobile_qq, String.valueOf(me.qq));
else if (me.isBind())
return NLS.bind(sms_title_bind_user, String.valueOf(me.qq));
else
return NLS.bind(sms_title_no_bind, String.valueOf(me.qq));
}
@Override
protected Image getImage() {
return res.getImage(Resources.icoMobile);
}
@Override
protected IQQListener getQQListener() {
return this;
}
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
initializeFriendSelectionShell(newShell);
}
private void initializeFriendSelectionShell(Shell newShell) {
fss = new FriendSelectionShell(newShell, false);
fss.addFriendSelectionListener(this);
fss.setModel(main.getBlindHelper().getSMSReceivableGroupList());
}
@Override
protected Point getInitialSize() {
return new Point(500, 450);
}
@Override
protected Control createContents(Composite parent) {
Composite control = getContentContainer();
Composite container = new Composite(control, SWT.NONE);
container.setBackground(Colors.WHITE);
container.setLayoutData(new GridData(GridData.FILL_BOTH));
container.setLayout(new GridLayout());
container.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
Composite c = (Composite) e.getSource();
Rectangle rect = c.getClientArea();
rect.width--;
rect.height--;
e.gc.setForeground(Colors.MAINSHELL_BORDER_OUTMOST);
e.gc.drawRectangle(rect);
}
});
UITool.setDefaultBackground(Colors.WHITE);
GridLayout layout = new GridLayout(2, false);
layout.marginHeight = 1;
Composite top = UITool.createContainer(container, new GridData(GridData.FILL_HORIZONTAL), layout);
top.addPaintListener(new CenterBorderPaintListener(new Class[] { Text.class }, 16, Colors.PAGE_CONTROL_BORDER));
// 收件人
Slat btnReceiver = new Slat(top);
btnReceiver.setText(sms_to);
btnReceiver.setLayoutData(new GridData());
btnReceiver.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
if (fss.isVisible())
fss.setVisible(false);
else {
if (fss == null || fss.isDisposed())
initializeFriendSelectionShell(getShell());
fss.setVisible(true);
}
}
});
btnReceiver.setEnabled(!singleMode);
textReceiver = new Text(top, SWT.SINGLE | (singleMode ? SWT.READ_ONLY : SWT.NONE));
textReceiver.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
layout = new GridLayout();
layout.marginHeight = layout.marginWidth = 3;
layout.verticalSpacing = 0;
Composite center = UITool.createContainer(container, new GridData(GridData.FILL_BOTH), layout);
center.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
Composite c = (Composite) e.getSource();
Rectangle rect = c.getClientArea();
rect.width--;
rect.height--;
e.gc.setForeground(Colors.MAINSHELL_BORDER_OUTMOST);
e.gc.drawRectangle(rect);
}
});
outputBox = new RichBox(center);
outputBox.setLayoutData(new GridData(GridData.FILL_BOTH));
outputBox.setReadonly(true);
outputBox.setBackground(Colors.WHITE);
outputBox.setDefaultStyle(myStyle);
// sash
Sash sash = new Sash(center, SWT.HORIZONTAL);
sash.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
sash.setBackground(Colors.READONLY_BACKGROUND);
sash.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
GridData data = (GridData) inputBox.getLayoutData();
data.heightHint = inputBox.getParent().getClientArea().height - e.y - 23;
inputBox.getParent().layout();
}
});
// 提示条
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.heightHint = 20;
Composite hintContainer = UITool.createContainer(center, gd, new GridLayout());
hintContainer.setBackground(Colors.VIEWFORM_BANNER_BACKGROUND);
lblHint = UITool.createLabel(hintContainer, NLS.bind(sms_will_send, String.valueOf(1)), new GridData(GridData.FILL_HORIZONTAL
| GridData.VERTICAL_ALIGN_CENTER));
lblHint.setBackground(lblHint.getParent().getBackground());
inputBox = new RichBox(center);
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.heightHint = 100;
inputBox.setLayoutData(gd);
inputBox.setBackground(Colors.WHITE);
inputBox.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
calculateFragmentCount();
refreshHint();
}
});
layout = new GridLayout(4, false);
layout.marginHeight = layout.marginWidth = 1;
Composite bottom = UITool.createContainer(container, new GridData(GridData.FILL_HORIZONTAL), layout);
bottom.addPaintListener(new CenterBorderPaintListener(new Class[] { Text.class }, 16, Colors.PAGE_CONTROL_BORDER));
// 聊天记录
gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.grabExcessHorizontalSpace = true;
Slat btnRecord = UITool.createSlat(bottom, button_record_accel, gd);
btnRecord.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
Slat temp = (Slat) e.getSource();
if (e.x > temp.getSize().x || e.y > temp.getSize().y || e.x < 0 || e.y < 0) {
return;
}
showRecord();
}
});
// 签名
UITool.createLabel(bottom, sms_sender, new GridData(GridData.HORIZONTAL_ALIGN_END));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -