/*
* Kontalk Java client
* Copyright (C) 2016 Kontalk Devteam <devteam@kontalk.org>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
package org.kontalk.view;
import javax.swing.Box;
import javax.swing.ListSelectionModel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Optional;
import com.alee.extended.panel.GroupPanel;
import com.alee.extended.panel.GroupingType;
import com.alee.laf.label.WebLabel;
import com.alee.laf.menu.WebMenuItem;
import com.alee.laf.menu.WebPopupMenu;
import com.alee.managers.language.data.TooltipWay;
import com.alee.managers.tooltip.TooltipManager;
import org.apache.commons.lang.StringEscapeUtils;
import org.kontalk.model.Contact;
import org.kontalk.model.Model;
import org.kontalk.model.chat.Chat;
import org.kontalk.persistence.Config;
import org.kontalk.system.Control;
import org.kontalk.util.Tr;
/**
* Display all contacts in a brief list.
* @author Alexander Bikadorov {@literal <bikaejkb@mail.tu-berlin.de>}
*/
final class ContactListView extends ListView<Contact> {
private final Model mModel;
ContactListView(final View view, Model model) {
super(view,
new FlyweightContactItem(),
new FlyweightContactItem(),
ListSelectionModel.SINGLE_SELECTION,
true,
true);
mModel = model;
// actions triggered by mouse events
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
Contact contact = ContactListView.this.getSelectedValue().orElse(null);
if (contact != null)
mView.showChat(contact);
}
}
});
this.updateOnEDT(null);
}
@Override
public int compare(Contact o1, Contact o2) {
return Utils.compareContacts(o1, o2);
}
@Override
protected void updateOnEDT(Object arg) {
boolean hideBlocked = Config.getInstance()
.getBoolean(Config.VIEW_HIDE_BLOCKED);
this.sync(Utils.allContacts(mModel.contacts(), !hideBlocked));
}
@Override
protected void selectionChanged(Optional<Contact> optContact) {
mView.onContactSelectionChanged(optContact);
}
@Override
protected WebPopupMenu rightClickMenu(List<Contact> selectedValues) {
WebPopupMenu menu = new WebPopupMenu();
if (selectedValues.isEmpty())
return menu;
Contact value = selectedValues.get(0);
WebMenuItem newItem = new WebMenuItem(Tr.tr("New Chat"));
newItem.setToolTipText(Tr.tr("Creates a new chat for this contact"));
newItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
Chat chat = mView.getControl().getOrCreateSingleChat(value);
mView.showChat(chat);
}
});
menu.add(newItem);
WebMenuItem blockItem = new WebMenuItem(Tr.tr("Block Contact"));
blockItem.setToolTipText(Tr.tr("Block all messages from this contact"));
blockItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
mView.getControl().sendContactBlocking(value, true);
}
});
menu.add(blockItem);
WebMenuItem unblockItem = new WebMenuItem(Tr.tr("Unblock Contact"));
unblockItem.setToolTipText(Tr.tr("Unblock this contact"));
unblockItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
mView.getControl().sendContactBlocking(value, false);
}
});
menu.add(unblockItem);
WebMenuItem deleteItem = new WebMenuItem(Tr.tr("Delete Contact"));
deleteItem.setToolTipText(Tr.tr("Delete this contact"));
deleteItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
String text = Tr.tr("Permanently delete this contact?") + "\n" +
mView.tr_remove_contact;
if (!Utils.confirmDeletion(ContactListView.this, text))
return;
mView.getControl().deleteContact(value);
}
});
menu.add(deleteItem);
// dont allow creation of more than one chat for a contact
newItem.setVisible(!mModel.chats().contains(value));
if (value.isBlocked()) {
blockItem.setVisible(false);
unblockItem.setVisible(true);
} else {
blockItem.setVisible(true);
unblockItem.setVisible(false);
}
Control.Status status = mView.currentStatus();
boolean connected = status == Control.Status.CONNECTED;
blockItem.setEnabled(connected);
unblockItem.setEnabled(connected);
deleteItem.setEnabled(connected);
return menu;
}
@Override
protected String getTooltipText(Contact value) {
String html = "<html><body>";
//"<h3>Header</h3>" +
if (value.getOnline() == Contact.Online.YES)
html += Tr.tr("Online") + "<br>";
if (!value.getStatus().isEmpty()) {
String status = StringEscapeUtils.escapeHtml(value.getStatus());
html += Tr.tr("Status") + ": " + status + "<br>";
}
if (value.getOnline() != Contact.Online.YES) {
html += Utils.lastSeen(value, true, false) + "<br>";
}
if (value.isBlocked()) {
html += Tr.tr("Contact is blocked!") + "<br>";
}
html += "</body></html>" ;
return html;
}
@Override
protected void onRenameEvent() {
Contact contact = this.getSelectedValue().orElse(null);
if (contact == null)
return;
mView.requestRenameFocus(contact);
}
private static class FlyweightContactItem extends ListView.FlyweightItem<Contact> {
private final ComponentUtils.AvatarImage mAvatar;
private final WebLabel mNameLabel;
private final WebLabel mStatusLabel;
FlyweightContactItem() {
//this.setPaintFocus(true);
this.setLayout(new BorderLayout(View.GAP_DEFAULT, 0));
this.setMargin(View.MARGIN_SMALL);
mAvatar = new ComponentUtils.AvatarImage(View.AVATAR_LIST_SIZE);
this.add(mAvatar, BorderLayout.WEST);
mNameLabel = new WebLabel();
mNameLabel.setFontSize(View.FONT_SIZE_BIG);
mNameLabel.setDrawShade(true);
mStatusLabel = new WebLabel();
mStatusLabel.setForeground(Color.GRAY);
mStatusLabel.setFontSize(View.FONT_SIZE_TINY);
this.add(
new GroupPanel(View.GAP_SMALL, false,
mNameLabel,
new GroupPanel(GroupingType.fillFirst,
Box.createGlue(), mStatusLabel)
), BorderLayout.CENTER);
}
@Override
protected void render(Contact value, int listWidth, boolean isSelected, boolean isLast) {
// avatar
mAvatar.setAvatarImage(value);
// name
String name = Utils.displayName(value);
if (!name.equals(mNameLabel.getText())) {
mNameLabel.setText(name);
}
// status
mStatusLabel.setText(Utils.mainStatus(value, isSelected));
// online status / background
Contact.Subscription subStatus = value.getSubScription();
this.setBackground(isSelected ? View.BLUE :
value.getOnline() == Contact.Online.YES ? View.LIGHT_BLUE:
subStatus == Contact.Subscription.UNSUBSCRIBED ||
subStatus == Contact.Subscription.PENDING ||
value.isBlocked() ? View.LIGHT_GREY :
Color.WHITE);
// tooltip
// TODO blocks mouse clicks interaction
if (true) return;
String html = "<html><body>";
//"<h3>Header</h3>" +
if (value.getOnline() == Contact.Online.YES)
html += Tr.tr("Online") + "<br>";
if (!value.getStatus().isEmpty()) {
String status = StringEscapeUtils.escapeHtml(value.getStatus());
html += Tr.tr("Status") + ": " + status + "<br>";
}
if (value.getOnline() != Contact.Online.YES) {
html += Utils.lastSeen(value, true, false) + "<br>";
}
if (value.isBlocked()) {
html += Tr.tr("Contact is blocked!") + "<br>";
}
html += "</body></html>" ;
TooltipManager.setTooltip(this, html, TooltipWay.right);
}
}
}