package ru.denull.wire;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.*;
import java.util.HashMap;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.text.Document;
import javax.swing.text.View;
import ru.denull.mtproto.DataService;
import ru.denull.mtproto.Server;
import ru.denull.wire.model.FileManager;
import ru.denull.wire.model.MessageListModel;
import ru.denull.wire.model.FileManager.FileLoadingCallback;
import tl.*;
import tl.Dialog;
import tl.contacts.ImportedContacts;
import tl.storage.TFileType;
public class MessageCellRenderer implements ListCellRenderer {
private DataService service;
private TInputPeer peer;
public HashMap<Integer, Component> cache = new HashMap<Integer, Component>();
public MessageCellRenderer(DataService service, TInputPeer peer) {
this.service = service;
this.peer = peer;
}
public Component getListCellRendererComponent(final JList list, Object item, final int index, boolean selected, boolean focused) {
GridBagConstraints constr;
final MessageListModel model = (MessageListModel) list.getModel();
final long modelState = model.getState();
if (item instanceof String) {
JLabel label = new JLabel((String) item, SwingConstants.CENTER);
label.setOpaque(true);
label.setForeground(Color.decode("0x80879b"));
label.setBackground(Color.decode("0xdfe8ef"));
label.setFont(new Font(Utils.fontName, Font.PLAIN, 18));
label.setBorder(new EmptyBorder(50, 4, 50, 4));
return label;
} else
if (item instanceof Integer) {
JLabel label = (JLabel) cache.get(-(Integer) item);
if (label == null) {
label = new JLabel(Utils.toDay((Integer) item), SwingConstants.CENTER);
label.setOpaque(true);
label.setForeground(Color.decode("0x80879b"));
label.setBackground(Color.decode("0xdfe8ef"));
label.setFont(new Font(Utils.fontName, Font.PLAIN, 12));
label.setBorder(new EmptyBorder(4, 4, 4, 4));
cache.put(-(Integer) item, label);
}
return label;
} else {
final TMessage message = (TMessage) item;
Component comp = cache.get(message.id);
if (comp != null) {
//System.out.println("returned " + message.id + ": " + comp);
return comp;
}
if (message instanceof MessageService) {
JLabel label = new JLabel(Utils.getServiceMessageDesc(service, message), SwingConstants.CENTER);
label.setOpaque(true);
label.setForeground(Color.decode("0x80879b"));
label.setBackground(Color.decode("0xdfe8ef"));
label.setFont(new Font(Utils.fontName, Font.PLAIN, 12));
label.setBorder(new EmptyBorder(4, 4, 4, 4));
cache.put(message.id, label);
return label;
}
MessageLayout layout = new MessageLayout(list, !message.out);
JPanel panel = new JPanel(layout);
panel.setBackground(Color.decode("0xdfe8ef"));
JLabel timeLabel = new JLabel(Utils.toTime(message.date));
timeLabel.setForeground(Color.decode("0x80879b"));
timeLabel.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
panel.add(timeLabel, MessageLayout.DATE);
if (message.out) {
if (message.failed) {
timeLabel.setIcon(new ImageIcon(Utils.getImage("msg_warning.png")));
} else if (message.sending) {
timeLabel.setIcon(new ImageIcon(Utils.getImage("msg_clock.png")));
} else if (message.unread) {
timeLabel.setIcon(new ImageIcon(Utils.getImage("msg_check.png")));
} else {
timeLabel.setIcon(new ImageIcon(Utils.getImage("msg_dblcheck.png")));
}
}
if (!message.out) {
if (peer instanceof InputPeerChat) {
ImagePanel photoPanel = new ImagePanel();
photoPanel.setPreferredSize(new Dimension(32, 32));
panel.add(photoPanel, MessageLayout.PHOTO);
service.userManager.getUserpic(message.from_id, photoPanel, false, new FileLoadingCallback() {
public void fail() { }
public void complete(TFileType type, Object data) {
cache.remove(message.id);
Object o = model.getSize() > index ? model.getElementAt(index) : null;
if (o != null && o instanceof TMessage && ((TMessage) o).id == message.id) {
model.updateContents(index);
} else {
model.updateContents();
}
}
});
}
}
if (message.media instanceof MessageMediaEmpty) {
/*JLabel bodyLabel = new JLabel(Utils.parseEmoji(
message.message,
(!message.out && peer instanceof InputPeerChat) ? service.userManager.get(message.from_id) : null,
(message instanceof MessageForwarded) ? service.userManager.get(((MessageForwarded) message).fwd_from_id) : null,
true));
bodyLabel.setVerticalAlignment(SwingConstants.TOP);
//bodyLabel.setMaximumSize(new Dimension());
Utils.fixEmoji(bodyLabel);*/
/*JTextPane bodyLabel = new JTextPane();
bodyLabel.setContentType("text/html");
bodyLabel.setText(Utils.parseEmoji(
message.message,
(!message.out && peer instanceof InputPeerChat) ? service.userManager.get(message.from_id) : null,
(message instanceof MessageForwarded) ? service.userManager.get(((MessageForwarded) message).fwd_from_id) : null,
true));
bodyLabel.setOpaque(false);
Utils.fixEmoji(bodyLabel);*/
TUser from = (!message.out && peer instanceof InputPeerChat) ? service.userManager.get(message.from_id) : null;
String fromName = null;
Color fromColor = null;
if (from != null) {
fromColor = Color.decode("0x" + Utils.userColors[from.id & 7]);
fromName = from.first_name + " " + from.last_name;
}
TUser forw = (message instanceof MessageForwarded) ? service.userManager.get(((MessageForwarded) message).fwd_from_id) : null;
String forwName = null;
Color forwColor = null;
if (forw != null) {
forwColor = Color.decode("0x006fc8");
forwName = "Пересланное сообщение\n" + forw.first_name + " " + forw.last_name;
}
EmojiLabel bodyLabel = new EmojiLabel(message.message, fromName, fromColor, forwName, forwColor);
bodyLabel.setForeground(Color.DARK_GRAY);
JPanel bodyPanel = new JPanel(new BorderLayout());
bodyPanel.setOpaque(false);
bodyPanel.setBorder(message.out ?
new NinePatchBorder(Utils.getImage("msg_out.png"), 4, 4, 31, 13, 4, 8, 4, 14) :
new NinePatchBorder(Utils.getImage("msg_in.png"), 4, 13, 31, 4, 4, 17, 4, 5));
bodyPanel.add(bodyLabel, BorderLayout.CENTER);
//bodyLabel.setMinimumSize(new Dimension(32, 28));
layout.setHTMLBody(bodyLabel, 8, 22);
panel.add(bodyPanel, MessageLayout.BODY);
} else
if (message.media instanceof MessageMediaPhoto) {
MessageMediaPhoto media = ((MessageMediaPhoto) message.media);
ImagePanel thumbPanel = new ImagePanel();
thumbPanel.setBorder(message.out ?
new NinePatchBorder(Utils.getImage("msg_out.png"), 4, 4, 31, 13, 4, 4, 4, 13) :
new NinePatchBorder(Utils.getImage("msg_in.png"), 4, 13, 31, 4, 4, 13, 4, 4));
panel.add(thumbPanel, MessageLayout.BODY);
Image thumbnail = null;
int maxw = 0;
int maxh = 0;
for (TPhotoSize size : ((Photo) media.photo).sizes) {
maxw = Math.max(maxw, size.w);
maxh = Math.max(maxh, size.h);
}
final int _maxw = maxw;
final int _maxh = maxh;
if (message.preview != null) { // uploading photo
thumbnail = message.preview;
thumbPanel.setPreferredSize(getOptimalSize(thumbnail.getWidth(null), thumbnail.getHeight(null)));
} else {
thumbnail = media.getThumbnail();
for (TPhotoSize size : ((Photo) media.photo).sizes) {
if (size instanceof PhotoSize) {
String type = ((PhotoSize) size).type;
if (type.equals("x") || type.equals("y") || type.equals("w")) {
thumbPanel.setPreferredSize(getOptimalSize(size.w, size.h));
break;
}
}
}
}
thumbPanel.setMaximumSize(new Dimension(maxw, maxh));
final TFileLocation location = media.getFullsize();
final TFileLocation hires = media.getMaxsize();
int state = service.fileManager.getState(location);
JProgressBar progressBar;
switch (state & FileManager.STATE_LOADING_MASK) {
case FileManager.STATE_NOT_LOADING:
/*JButton downloadBtn = new JButton("Загрузить");
downloadBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
panel.add(downloadBtn, MessageLayout.ACTIONS);*/
progressBar = new JProgressBar();
progressBar.setValue(0);
//panel.add(progressBar, MessageLayout.ACTIONS);
thumbPanel.setImage(thumbnail);
service.fileManager.query(location, new FileLoadingCallback() {
public void fail() {
// nothing
}
public void complete(TFileType type, Object data) {
cache.remove(message.id);
if (model.getState() == modelState) {
model.updateContents(index);
//list.repaint(list.getCellBounds(index, index));
} else {
model.updateContents();
}
}
});
break;
case FileManager.STATE_QUEUED:
case FileManager.STATE_IN_PROGRESS:
progressBar = new JProgressBar();
progressBar.setValue(state & FileManager.STATE_PROGRESS_MASK);
//panel.add(progressBar, MessageLayout.ACTIONS);
thumbPanel.setImage(thumbnail);
break;
case FileManager.STATE_COMPLETE:
service.fileManager.queryImage(location, thumbPanel);
break;
}
JPanel actionPanel = new JPanel();
actionPanel.setBackground(Color.decode("0xdfe8ef"));
actionPanel.setLayout(new BoxLayout(actionPanel, BoxLayout.X_AXIS));
JButton openBtn = new JButton("открыть");
//openBtn.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
openBtn.setForeground(Color.DARK_GRAY);
openBtn.putClientProperty("JButton.buttonType", "roundRect");
openBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFrame frame = new JFrame("Просмотр");
ImagePanel panel = new ImagePanel();
//panel.setPreferredSize(new Dimension(_maxw, _maxh));
service.fileManager.queryImage(hires, panel);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setSize(_maxw, _maxh);
frame.setVisible(true);
}
});
actionPanel.add(openBtn);
actionPanel.add(Box.createRigidArea(new Dimension(2, 0)));
JButton saveBtn = new JButton("сохранить...");
//openBtn.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
saveBtn.setForeground(Color.DARK_GRAY);
saveBtn.putClientProperty("JButton.buttonType", "roundRect");
saveBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Main.saveDialog.setFile("photo.jpg");
Main.saveDialog.setVisible(true);
String filename = Main.saveDialog.getFile();
if (filename != null) {
service.fileManager.queryFile(hires, Main.saveDialog.getDirectory() + System.getProperty("file.separator") + Main.saveDialog.getFile());
}
}
});
actionPanel.add(saveBtn);
panel.add(actionPanel, MessageLayout.ACTIONS);
/*Button btnLoad = ViewHolder.get(convertView, R.id.btn_load);
btnLoad.setTag(message);
View progressBlock = ViewHolder.get(convertView, R.id.progress_block);
TFileLocation location = media.getFullsize();
int state = service.fileManager.getState(location);
switch (state & FileManager.STATE_LOADING_MASK) {
case FileManager.STATE_NOT_LOADING:
btnLoad.setVisibility(View.VISIBLE);
btnLoad.setText(activity.getResources().getString(R.string.download, ""));
progressBlock.setVisibility(View.INVISIBLE);
break;
case FileManager.STATE_QUEUED:
case FileManager.STATE_IN_PROGRESS:
btnLoad.setVisibility(View.INVISIBLE);
progressBlock.setVisibility(View.VISIBLE);
ProgressBar progress = ViewHolder.get(progressBlock, R.id.progress);
progress.setProgress(state & FileManager.STATE_PROGRESS_MASK);
break;
case FileManager.STATE_COMPLETE:
service.fileManager.queryImage(location, thumb);
btnLoad.setVisibility(View.VISIBLE);
btnLoad.setText(activity.getResources().getString(R.string.view_photo, ""));
progressBlock.setVisibility(View.INVISIBLE);
break;
}*/
} else
if (message.media instanceof MessageMediaVideo) {
MessageMediaVideo media = ((MessageMediaVideo) message.media);
ImagePanel thumbPanel = new ImagePanel();
thumbPanel.setBorder(message.out ?
new NinePatchBorder(Utils.getImage("msg_out.png"), 4, 4, 31, 13, 4, 4, 4, 13) :
new NinePatchBorder(Utils.getImage("msg_in.png"), 4, 13, 31, 4, 4, 13, 4, 4));
panel.add(thumbPanel, MessageLayout.BODY);
final Video video = (Video) media.video;
thumbPanel.setImage(media.getThumbnail());
thumbPanel.setBackground(Color.BLACK);
thumbPanel.setPreferredSize(getOptimalSize(video.w, video.h));
thumbPanel.setMaximumSize(new Dimension(video.w, video.h));
JButton saveBtn = new JButton("сохранить...");
//openBtn.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
saveBtn.setForeground(Color.DARK_GRAY);
saveBtn.putClientProperty("JButton.buttonType", "roundRect");
saveBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Main.saveDialog.setFile("video.mov");
Main.saveDialog.setVisible(true);
String filename = Main.saveDialog.getFile();
if (filename != null) {
service.fileManager.queryFile(video, Main.saveDialog.getDirectory() + System.getProperty("file.separator") + Main.saveDialog.getFile());
}
}
});
panel.add(saveBtn, MessageLayout.ACTIONS);
/*Button btnLoad = ViewHolder.get(convertView, R.id.btn_load);
btnLoad.setTag(message);
View progressBlock = ViewHolder.get(convertView, R.id.progress_block);
int state = service.fileManager.getState(video);
switch (state & FileManager.STATE_LOADING_MASK) {
case FileManager.STATE_NOT_LOADING:
btnLoad.setVisibility(View.VISIBLE);
btnLoad.setText(activity.getResources().getString(R.string.download, Utils.toSize(video.size)));
progressBlock.setVisibility(View.INVISIBLE);
break;
case FileManager.STATE_QUEUED:
case FileManager.STATE_IN_PROGRESS:
btnLoad.setVisibility(View.INVISIBLE);
progressBlock.setVisibility(View.VISIBLE);
ProgressBar progress = ViewHolder.get(progressBlock, R.id.progress);
progress.setProgress(state & FileManager.STATE_PROGRESS_MASK);
break;
case FileManager.STATE_COMPLETE:
btnLoad.setVisibility(View.VISIBLE);
btnLoad.setText(activity.getResources().getString(R.string.view_video, ""));
progressBlock.setVisibility(View.INVISIBLE);
break;
}
ImageView icVideo = ViewHolder.get(convertView, R.id.ic_video);
TextView duration = ViewHolder.get(convertView, R.id.duration);
icVideo.setVisibility(View.VISIBLE);
duration.setVisibility(View.VISIBLE);
duration.setText(Utils.toDuration(video.duration));*/
} else
if (message.media instanceof MessageMediaGeo) {
ImagePanel thumbPanel = new ImagePanel();
thumbPanel.setBorder(message.out ?
new NinePatchBorder(Utils.getImage("msg_out.png"), 4, 4, 31, 13, 4, 4, 4, 13) :
new NinePatchBorder(Utils.getImage("msg_in.png"), 4, 13, 31, 4, 4, 13, 4, 4));
panel.add(thumbPanel, MessageLayout.BODY);
thumbPanel.setPreferredSize(new Dimension(377, 248));
try {
thumbPanel.setImage(ImageIO.read(new URL(
"http://maps.googleapis.com/maps/api/staticmap?" +
"center=" + message.media.geo.lat + "," + message.media.geo.lng + "&" +
"markers=color:red%7C" + message.media.geo.lat + "," + message.media.geo.lng + "&" +
"zoom=14&" +
"size=360x240&" +
"maptype=roadmap&" +
"sensor=false&" +
"visual_refresh=true")));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
JPanel actionPanel = new JPanel();
actionPanel.setBackground(Color.decode("0xdfe8ef"));
actionPanel.setLayout(new BoxLayout(actionPanel, BoxLayout.X_AXIS));
JButton yandexBtn = new JButton("Яндекс");
//openBtn.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
yandexBtn.setForeground(Color.DARK_GRAY);
yandexBtn.putClientProperty("JButton.buttonType", "roundRect");
yandexBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Utils.openWebpage(new URI("http://maps.yandex.ru/?ll=" + message.media.geo.lng + "%2C" + message.media.geo.lat + "&z=16&l=map"));
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
}
});
actionPanel.add(yandexBtn);
actionPanel.add(Box.createRigidArea(new Dimension(2, 0)));
JButton googleBtn = new JButton("Google");
//openBtn.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
googleBtn.setForeground(Color.DARK_GRAY);
googleBtn.putClientProperty("JButton.buttonType", "roundRect");
googleBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Utils.openWebpage(new URI("http://google.com/maps?q=" + message.media.geo.lat + "," + message.media.geo.lng));
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
}
});
actionPanel.add(googleBtn);
panel.add(actionPanel, MessageLayout.ACTIONS);
/*ImageButton thumb = ViewHolder.get(convertView, R.id.thumb);
thumb.setImageBitmap(null);
Button btnLoad = ViewHolder.get(convertView, R.id.btn_load);
btnLoad.setTag(message);
View progressBlock = ViewHolder.get(convertView, R.id.progress_block);
btnLoad.setVisibility(View.VISIBLE);
btnLoad.setText(activity.getResources().getString(R.string.view_location, ""));
progressBlock.setVisibility(View.INVISIBLE);*/
} else
if (message.media instanceof MessageMediaContact) {
TUser from = (!message.out && peer instanceof InputPeerChat) ? service.userManager.get(message.from_id) : null;
String fromName = null;
Color fromColor = null;
if (from != null) {
fromColor = Color.decode("0x" + Utils.userColors[from.id & 7]);
fromName = from.first_name + " " + from.last_name;
}
String forwName = "Контакт\n" + message.media.first_name + " " + message.media.last_name;
Color forwColor = Color.decode("0x006fc8");
EmojiLabel bodyLabel = new EmojiLabel(message.media.phone_number, fromName, fromColor, forwName, forwColor);
JPanel bodyPanel = new JPanel(new BorderLayout());
bodyPanel.setOpaque(false);
bodyPanel.setBorder(message.out ?
new NinePatchBorder(Utils.getImage("msg_out.png"), 4, 4, 31, 13, 4, 8, 4, 14) :
new NinePatchBorder(Utils.getImage("msg_in.png"), 4, 13, 31, 4, 4, 17, 4, 5));
bodyPanel.add(bodyLabel, BorderLayout.CENTER);
layout.setHTMLBody(bodyLabel, 8, 25);
panel.add(bodyPanel, MessageLayout.BODY);
final MessageMediaContact contact = (MessageMediaContact) message.media;
if (!service.contactManager.loaded.containsKey(-contact.user_id)) {
final JButton importBtn = new JButton("добавить");
//openBtn.setFont(new Font(Utils.fontName, Font.PLAIN, 11));
importBtn.setForeground(Color.DARK_GRAY);
importBtn.putClientProperty("JButton.buttonType", "roundRect");
importBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
service.mainServer.call(new tl.contacts.ImportContacts(
new TInputContact[] { new InputPhoneContact(0, contact.phone_number, contact.first_name, contact.last_name) }, false),
new Server.RPCCallback<ImportedContacts>() {
public void done(ImportedContacts result) {
if (result.imported.length > 0) {
Main.contactListModel.add(result.imported[0].user_id, true);
}
if (model.getState() == modelState) {
model.updateContents(index);
//list.repaint(list.getCellBounds(index, index));
} else {
model.updateContents();
}
}
public void error(int code, String message) {
}
});
}
});
panel.add(importBtn, MessageLayout.ACTIONS);
}
}
if (message.out) {
/*ImageView status = ViewHolder.get(convertView, R.id.status);
if (message.media instanceof MessageMediaEmpty) {
if (message.failed) {
status.setImageResource(R.drawable.msg_warning);
} else if (message.sending) {
status.setImageResource(R.drawable.msg_clock);
} else if (message.unread) {
status.setImageResource(R.drawable.msg_check);
} else {
status.setImageResource(R.drawable.msg_check_comp);
}
} else {
if (message.failed) {
status.setImageResource(R.drawable.msg_warning);
} else if (message.sending) {
status.setImageResource(R.drawable.msg_check_photo);
} else if (message.unread) {
status.setImageResource(R.drawable.msg_check_photo);
} else {
status.setImageResource(R.drawable.msg_check_photo_comp);
}
}*/
}
cache.put(message.id, panel);
return panel;
}
}
private Dimension getOptimalSize(int w, int h) {
// Try to set fixed area first (100 kilopixels), so all pictures look roughly same size
int optw = (int) Math.sqrt(200000f * w / h);
int opth = (int) Math.sqrt(200000f * h / w);
// We don't want to upscale images
optw = Math.min(optw, w);
opth = Math.min(opth, h);
// We don't need to think about width - MessageLayout scales image as needed, but we want to limit height here
if (opth > 500) {
opth = 500;
optw = w * 500 / h;
}
return new Dimension(17 + optw, 8 + opth);
}
}