📄 chatdialog.java
字号:
/*
* @(#)ChatDialog.java
*
* Copyright (c) 2002, Jang-Ho Hwang
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Jang-Ho Hwang nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: ChatDialog.java,v 1.36 2003/02/06 10:51:09 xrath Exp $
*/
package rath.jmsn.ui;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;
import java.util.Hashtable;
import javax.swing.*;
import javax.swing.filechooser.*;
import javax.swing.text.*;
import rath.msnm.UserStatus;
import rath.msnm.LocalCopy;
import rath.msnm.MSNMessenger;
import rath.msnm.SwitchboardSession;
import rath.msnm.event.MsnAdapter;
import rath.msnm.entity.MsnFriend;
import rath.msnm.msg.MimeMessage;
import rath.msnm.msg.MimeUtility;
import rath.msnm.ftp.VolatileDownloader;
import rath.msnm.ftp.VolatileTransferServer;
import rath.jmsn.ToolBox;
import rath.jmsn.MainFrame;
import rath.jmsn.NativeToolkit;
import rath.jmsn.entity.FileItem;
import rath.jmsn.file.FileProgress;
import rath.jmsn.file.ChatLogWriter;
import rath.jmsn.util.MusicBox;
import rath.jmsn.util.Msg;
import rath.util.HangulJamoUtil;
/**
* 措拳且锭 荤侩登绰 促捞倔肺弊捞促.
*
* @author Jang-Ho Hwang, rath@linuxkorea.co.kr
* @version $Id: ChatDialog.java,v 1.36 2003/02/06 10:51:09 xrath Exp $
*/
public class ChatDialog extends JFrame implements ToolBox, DialogAppender
{
private static final SimpleDateFormat ts = new SimpleDateFormat("[HH:mm]" );
private static final SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
private MSNMessenger msnm = null;
private MsnFriend me = null;
private JScrollPane chatPane = null;
private JScrollPane inputPane = null;
private JButton filesendButton = null;
private ChatArea chatArea = null;
private JTextArea inputArea = null;
private JLabel statusLabel = null;
private SwitchboardSession session = null;
private boolean isSessionClose = false;
private WindowListener wl = null;
private JPanel topPanel = null;
private MsnFriend you = null;
private ArrayList queue = new ArrayList();
private ChatLogWriter log = null;
private Vector fileQueue = new Vector();
private Hashtable fileCookieMap = new Hashtable();
private MsnAdapter fileAdapter = new FileAdapter();
private ArrayList historyQueue = new ArrayList();
private int historyIndex = -1;
private long lastMessagingTime = 0L;
private boolean isViewTimestamp = MainFrame.LOCALCOPY.getPropertyBoolean(MainFrame.TIMESTAMP_DISPLAY, false);
private boolean useFixedFont = MainFrame.LOCALCOPY.getPropertyBoolean(MainFrame.USE_FIXED_CHAT_FONT, false);
public ChatDialog( Frame owner, MSNMessenger msnm, String targetName, MsnFriend i )
{
setTitle( targetName );
this.me = i;
this.msnm = msnm;
init();
}
/**
* 惑措规栏肺何磐 率瘤芒捞 凯啡阑锭 荤侩登绰 constructor捞促.
*/
public ChatDialog( Frame owner, MSNMessenger msnm, SwitchboardSession session,
MsnFriend i )
{
setTitle( session.getMsnFriend().getLoginName() );
this.me = i;
this.you = session.getMsnFriend();
this.msnm = msnm;
this.session = session;
MusicBox.play( MusicBox.SOUND_MESSAGE_2 );
prepareLogWriter( you.getLoginName() );
init();
}
private void init()
{
createComponents();
createKeyMap();
this.addComponentListener( new DialogStatus() );
super.addWindowListener( new WindowAdapter() {
/**
* To fix focus problem in MacOS X
*/
public void windowActivated( WindowEvent e )
{
chatArea.requestFocus();
inputArea.requestFocus();
}
});
this.msnm.addMsnListener( fileAdapter );
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int)(Math.random() * (double)(size.height-getSize().width));
int y = (int)(Math.random() * (double)(size.height-getSize().height));
setLocation( x, y );
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
}
private void prepareLogWriter( String targetName )
{
if( this.log!=null )
return;
String logdir = msnm.getLocalCopy().getProperty( MainFrame.CHATLOG_PROP );
File file = new File( logdir, targetName + ".txt" );
try {
this.log = new ChatLogWriter( file );
} catch( IOException e ) { System.err.println( "can't write log file." ); }
}
private class FileAdapter extends MsnAdapter
{
public void fileReceiveStarted( VolatileDownloader down )
{
String cookie = down.getCookie();
FileProgress prog = null;
if( (prog=(FileProgress)fileCookieMap.remove(cookie))!=null )
{
prog.setTransfer( down );
}
}
public void fileSendStarted( VolatileTransferServer vts )
{
String cookie = vts.getCookie();
FileProgress prog = null;
if( (prog=(FileProgress)fileCookieMap.remove(cookie))!=null )
{
prog.setTransfer( vts );
}
}
public void fileSendError( VolatileTransferServer server, Throwable e )
{
e.printStackTrace();
}
public void fileSendAccepted( SwitchboardSession ss, int cookie )
{
if( session==null ) return;
if( ss.getSessionId().equals( session.getSessionId() ) )
{
final FileProgress prog = new FileProgress( ChatDialog.this );
fileCookieMap.put( String.valueOf(cookie), prog );
SwingUtilities.invokeLater( new Runnable() {
public void run()
{
topPanel.add( prog );
topPanel.doLayout();
topPanel.validate();
}
});
MimeMessage msg = new MimeMessage();
msg.setMessage( Msg.get("chatdlg.filesend.accept", you.getLoginName()) );
appendMessage( msg );
}
}
public void fileSendRejected( SwitchboardSession ss, int cookie, String reason )
{
if( session==null ) return;
if( ss.getSessionId().equals( session.getSessionId() ) )
{
MimeMessage msg = new MimeMessage();
msg.setMessage( Msg.get("chatdlg.filesend.reject", you.getLoginName()) );
appendMessage( msg );
}
}
}
public void addFileItem( final FileItem item )
{
fileQueue.add(item);
MimeMessage msg = new MimeMessage();
msg.setMessage( Msg.get("chatdlg.filerecv.notify",
you.getFormattedFriendlyName(), item.getName()+"("+item.getKBSize()+")") );
appendMessage( msg );
if( Boolean.getBoolean("jmsn.file.auto.accept") )
acceptFileRequest();
}
private void createKeyMap()
{
JPanel panel = (JPanel)getContentPane();
ComponentInputMap im = new ComponentInputMap(panel);
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK), "FileAccept" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_MASK), "FileAccept" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_MASK), "FileReject" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK), "FileReject" );
ActionMap am = panel.getActionMap();
am.put( "FileAccept", new AbstractAction() {
public void actionPerformed( ActionEvent e )
{
acceptFileRequest();
}
});
am.put( "FileReject", new AbstractAction() {
public void actionPerformed( ActionEvent e )
{
if( fileQueue.size()==0 )
return;
FileItem item = (FileItem)fileQueue.remove(0);
SwitchboardSession ss = item.getSession();
try {
ss.rejectFileReceive( item.getCookie() );
} catch( IOException ex ) { ex.printStackTrace(); }
MimeMessage msg = new MimeMessage();
msg.setMessage( Msg.get("chatdlg.filerecv.reject") );
appendMessage( msg );
}
});
panel.setInputMap( JComponent.WHEN_IN_FOCUSED_WINDOW, im );
addKeyListener( new KeyAdapter() {
public void keyPressed( KeyEvent e )
{
if( e.getKeyCode()==KeyEvent.VK_ESCAPE )
dispose();
}
});
}
private class DialogStatus extends ComponentAdapter
{
/*
public void componentShown( ComponentEvent e )
{
inputArea.requestFocus();
ChatDialog.this.show();
}
*/
public void componentResized( ComponentEvent e )
{
chatPane.getViewport().scrollRectToVisible(
new Rectangle(0, chatArea.getSize().height, 100, 100) );
}
}
private void acceptFileRequest()
{
if( fileQueue.size()==0 )
return;
FileItem item = (FileItem)fileQueue.remove(0);
SwitchboardSession ss = item.getSession();
LocalCopy local = msnm.getLocalCopy();
FileProgress prog = new FileProgress(this);
try
{
File file = new File(
local.getProperty(MainFrame.DOWNLOAD_PROP),
item.getName() );
fileCookieMap.put( String.valueOf(item.getCookie()), prog );
ss.acceptFileReceive( item.getCookie(), file );
}
catch( IOException ex ) { ex.printStackTrace(); }
topPanel.add( prog );
topPanel.doLayout();
topPanel.validate();
}
public void sessionClosed()
{
this.session = null;
isSessionClose = true;
}
public void userOffline()
{
if( you==null ) return;
MimeMessage msg = new MimeMessage();
msg.setMessage( Msg.get("chatdlg.msg.offline", you.getLoginName()) );
appendMessage( msg );
filesendButton.setEnabled( false );
inputArea.setEnabled( false );
//chatArea.requestFocus();
}
private void createComponents()
{
setSize( 350, 350 );
JPanel panel = (JPanel)getContentPane();
chatArea = new ChatArea() {
public void acceptFiles( List list )
{
for(Iterator i=list.iterator(); i.hasNext(); )
sendFileImpl( (File)i.next() );
}
public void inviteFriend( String loginName )
{
if( session!=null )
{
try
{
session.inviteFriend( loginName );
MimeMessage msg = new MimeMessage();
msg.setMessage( Msg.get("chatdlg.msg.invite", loginName) );
appendMessage( msg );
}
catch( IOException e ) {}
}
}
};
chatArea.setFont( FONT_10 );
chatArea.append( Msg.get("chatdlg.msg.top") );
JPanel propertyPane = new JPanel();
propertyPane.setLayout(new BorderLayout());
//propertyPane.setBackground(new Color(210,210,255));
JPanel propertyArea = new JPanel();
propertyArea.setPreferredSize( new Dimension(Short.MAX_VALUE,32));
propertyArea.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
JButton fontButton = new JButton( Msg.get("label.font"));
fontButton.setFont( FONT );
fontButton.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e )
{
showFontDialog();
}
});
fontButton.setToolTipText(Msg.get("label.font"));
propertyArea.add(fontButton);
JButton emoticonButton = new JButton( Msg.get("label.emoticon"));
emoticonButton.setFont( FONT );
emoticonButton.setToolTipText(Msg.get("label.emoticon"));
propertyPane.add(propertyArea, "West");
inputArea = new JTextArea();
inputArea.setFont( FONT_10 );
inputArea.setLineWrap( true );
statusLabel = new JLabel("");
statusLabel.setFont( FONT_10 );
statusLabel.setPreferredSize( new Dimension(100, 24) );
chatPane = new JScrollPane( chatArea);
inputPane = new JScrollPane( inputArea );
inputPane.setPreferredSize( new Dimension(100, 50) );
JPanel bottomPanel = new JPanel(new BorderLayout());
bottomPanel.add( propertyPane, "North");
bottomPanel.add( inputPane, "Center" );
bottomPanel.add( statusLabel, "South" );
topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 4));
topPanel.setPreferredSize( new Dimension(100,38) );
topPanel.setBorder( BorderFactory.createEtchedBorder() );
filesendButton = new JButton(Msg.get("button.file.send"));
filesendButton.setFont( FONT );
filesendButton.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e )
{
prepareSendFile();
}
});
topPanel.add( filesendButton );
panel.add( topPanel, "North" );
panel.add( chatPane, "Center" );
panel.add( bottomPanel, "South" );
InputMap im = inputArea.getInputMap();
ActionMap am = inputArea.getActionMap();
AbstractAction newlineAction = new AbstractAction()
{
public void actionPerformed( ActionEvent e )
{
inputArea.append("\n");
}
};
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_MASK), "newline" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK), "newline" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "send" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.ALT_MASK), "TopMost" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "HistoryUp" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD8, 0), "HistoryUp" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "HistoryDown" );
im.put( KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, 0), "HistoryDown" );
am.put( "newline", newlineAction );
am.put( "send", new AbstractAction() {
public void actionPerformed( ActionEvent e )
{
sendMessage();
}
});
am.put( "dispose", new AbstractAction() {
public void actionPerformed( ActionEvent e )
{
dispose();
}
});
am.put( "TopMost", new AbstractAction() {
boolean isTopMost = false;
public void actionPerformed( ActionEvent e )
{
NativeToolkit tk = NativeToolkit.getInstance();
tk.makeTopMost( ChatDialog.this, !isTopMost );
isTopMost = !isTopMost;
}
});
am.put( "HistoryUp", new AbstractAction() {
public void actionPerformed( ActionEvent e )
{
if( historyIndex==-1 )
return;
historyIndex--;
if( historyIndex<0 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -