package GUI;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import Control.Contact;
import Control.DateFormatter;
import Control.Message;
/**
* Displays the outgoing or incoming {@link Message}s. If assigned as a {@link JTextPane} for the outgoing
* messages it only has to provide the possibility of writing in. Otherwise has to take {@link Message}s
* and display them properly, with a reference on the time and the corresponding user.
*
* @author Sebastian
*
*/
public class SatedaTextPane extends JTextPane implements MouseListener{
/**
* <code>true</code> when it is used as an outgoing {@link JTextPane}, <code>false</code> otherwise
*/
private boolean outgoing;
private StyledDocument styleDoc;
/**
* The {@link Style} of the text messages
*/
private Style textStyle = new StyleContext().getStyle(StyleContext.DEFAULT_STYLE);
/**
* The style in which the name of the person writing the incoming message is displayed
*/
private Style incomingStyle = new StyleContext().getStyle(StyleContext.DEFAULT_STYLE);
/**
* The style in which the name of the person sending the outgoing message is displayed
*/
private Style outgoingStyle = new StyleContext().getStyle(StyleContext.DEFAULT_STYLE);
/**
* Is used to generate a little space between two lines of text
*/
private Style littleSpaceStyle = new StyleContext().getStyle(StyleContext.DEFAULT_STYLE);
/**
* Is used to generate a bigger space between two lines of text
*/
private Style biggerSpaceStyle = new StyleContext().getStyle(StyleContext.DEFAULT_STYLE);
/**
* The style used for the information about the start of the chat with a specific {@link Contact}
*/
private Style startInformationStyle = new StyleContext().getStyle(StyleContext.DEFAULT_STYLE);
/**
* The list of all {@link Message}s to be displayed in case the pane shall display the history
* of all incoming and outgoing messages
*/
private ArrayList<Message> messages = new ArrayList<Message>();
/**
* Indicates when the chat with the current {@link Contact} was started
*/
private Date dateChatStarted;
public SatedaTextPane(boolean outgoing, Date dateChatStarted) {
this.outgoing = outgoing;
this.dateChatStarted = dateChatStarted;
addMouseListener(this);
if( ! outgoing){
setEditable(false);
}else{
setFont(new Font("Verdana", Font.PLAIN, 12));
}
styleDoc = this.getStyledDocument();
StyleConstants.setFontSize(textStyle, 12);
StyleConstants.setFontFamily(textStyle, "Verdana");
StyleConstants.setFontSize(incomingStyle, 12);
StyleConstants.setFontFamily(incomingStyle, "Verdana");
StyleConstants.setForeground(incomingStyle, new Color(230, 84, 4));
StyleConstants.setFontSize(outgoingStyle, 12);
StyleConstants.setFontFamily(outgoingStyle, "Verdana");
StyleConstants.setForeground(outgoingStyle, new Color(96, 125, 193));
StyleConstants.setFontSize(littleSpaceStyle, 1);
StyleConstants.setFontSize(biggerSpaceStyle, 9);
StyleConstants.setFontSize(startInformationStyle, 11);
StyleConstants.setFontFamily(startInformationStyle, "Verdana");
StyleConstants.setForeground(startInformationStyle, new Color(113, 124, 175));
}
/**
* Deletes the reference on the current {@link Message}s, sets the forwarded one as current ones
* and refreshes the appearance accordingly.
*
* All information displayed will disappear and be replaced by the new ones.
*
* @param messages
*/
public void setMessages(ArrayList<Message> messages){
if( ! outgoing){
this.messages = messages;
clearContent();
if(messages.size() > 0){
refreshAppearance();
}
}
}
/**
* Adds a {@link Message} to the list of messages to be displayed. Then takes care
* that the new message is added to the already displayed ones.
*
* @param message
*/
public void addMessage(Message message){
if( ! outgoing){
messages.add(message);
clearContent();
refreshAppearance();
}
}
private void clearContent(){
try {
styleDoc.remove(0, styleDoc.getLength());
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/**
* Refreshes the appearance of the pane according to the list of {@link Message}s to be displayed.
* Clears the pane first before inserting the {@link Message}s.
*/
public void refreshAppearance(){
boolean firstElement = true;
boolean incomingOnFormer = false;
boolean showHeader = true;
Style headerStyle;
try {
String timeStarted = getDisplayedDate(dateChatStarted, true, false);
DateFormatter formattedDate = new DateFormatter(dateChatStarted);
styleDoc.insertString(styleDoc.getLength(), "Unterhaltung mit "
+ messages.get(0).getChatPartner().getDisplayedName() +" am "
+ formattedDate.getDay() + ". " + formattedDate.getMonthString()
+ " " + formattedDate.getYear() + " um "
+ timeStarted +" Uhr gestartet...", startInformationStyle);
styleDoc.insertString(styleDoc.getLength(), "\n\n", biggerSpaceStyle);
styleDoc.insertString(styleDoc.getLength(), "\n", littleSpaceStyle);
for(Message message : messages){
showHeader = true;
if( ! firstElement && message.isIncoming() != incomingOnFormer){
styleDoc.insertString(styleDoc.getLength(), "\n", biggerSpaceStyle);
}else if( ! firstElement){
if( ! isLongerOneMinute(message.getDate())){
styleDoc.insertString(styleDoc.getLength(), "\n", littleSpaceStyle);
styleDoc.insertString(styleDoc.getLength(), "\n", littleSpaceStyle);
styleDoc.insertString(styleDoc.getLength(), "\n", littleSpaceStyle);
showHeader = false;
}else{
styleDoc.insertString(styleDoc.getLength(), "\n", biggerSpaceStyle);
}
}
headerStyle = incomingStyle;
incomingOnFormer = true;
firstElement = false;
if( ! message.isIncoming()){
headerStyle = outgoingStyle;
incomingOnFormer = false;
}
String date = getDisplayedDate(message.getDate(), false, false);
if(showHeader){
styleDoc.insertString(styleDoc.getLength(),
message.getChatPartner().getDisplayedName() + " ("
+ date + ")\n", headerStyle);
styleDoc.insertString(styleDoc.getLength(), "\n", littleSpaceStyle);
}
styleDoc.insertString(styleDoc.getLength(), message.getText() + "\n", textStyle);
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
/**
* @param messageDate
*
* @return the forwarded {@link Date} according the way it shall be displayed behind the
* chat contacts name. If the date is on the same day as today only the time itself gets displayed,
* otherwise the day, month and year get added. That only is the case though when
* <code>returnTime</code> and <code>completeDate</code> are both <code>false</code>.
*
* <p>In case <code>returnTime</code> is <code>true</code> only the time gets returned</p>
* <p>In case <code>completeDate</code> is <code>true</code> the whole date gets returned</p>
*/
public String getDisplayedDate(Date messageDate, boolean returnTime, boolean completeDate){
DateFormatter formattedDate = new DateFormatter(messageDate);
String date = formattedDate.getHour() + ":" + formattedDate.getMinutes();
if(returnTime){
return date;
}
if( (! isToday(messageDate)) || completeDate){
String date2 = formattedDate.getDay() + ". " + formattedDate.getMonthString()
+ " " + formattedDate.getYear() + " - ";
date = date2 + date;
}
return date;
}
/**
*
* @param date
*
* @return <code>true</code> in case the forwarded date indicates a time more distant than one
* minute ago, <code>false</code> otherwise
*/
public boolean isLongerOneMinute(Date date){
Date now = new Date();
if(now.getTime() - date.getTime() > 1000){
return true;
}
return false;
}
/**
* @param date
*
* @return <code>true</code> when the forwarded date is on the current day, <code>false</code> otherwise
*/
private boolean isToday(Date date){
DateFormatter today = new DateFormatter(new Date());
DateFormatter forwarded = new DateFormatter(date);
if(today.getYear() == forwarded.getYear() && today.getDay() == forwarded.getDay()
&& today.getMonth() == forwarded.getMonth()){
return true;
}
return false;
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}