/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.plugin.notificationconfiguration;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.notification.event.*;
/**
* @author Alexandre Maillard
* @author Yana Stamcheva
*/
public class NotificationsTable
extends JScrollPane
implements NotificationChangeListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The enabled state of the notification action.
*/
public static final String ENABLED = "Enabled";
/**
* The disabled state of the notification action.
*/
public static final String DISABLED = "Disabled";
/**
* The notifications table.
*/
private final NotificationTable notifTable;
/**
* The notifications table model.
*/
private final NotificationsTableModel model;
/**
* The configuration panel.
*/
private final NotificationConfigurationPanel configPanel;
/**
* The notification service.
*/
private NotificationService notificationService = null;
/**
* Creates an instance of the <tt>NotificationsTable</tt>.
* @param columns an array containing all columns
* @param columnToolTips an array containing all column tooltips
* @param panel the parent configuration panel
*/
NotificationsTable( Object columns[],
String columnToolTips[],
NotificationConfigurationPanel panel)
{
configPanel = panel;
notificationService
= NotificationConfigurationActivator.getNotificationService();
notificationService.addNotificationChangeListener(this);
String strTmp = new String();
model = new NotificationsTableModel(columns, 0);
notifTable = new NotificationTable(model, columnToolTips);
notifTable.setRowSelectionAllowed(true);
notifTable.getTableHeader().setReorderingAllowed(false);
notifTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
notifTable.addMouseListener(new NotificationsCellListener());
notifTable.setDefaultRenderer( String.class,
new StringTableRenderer());
notifTable.setDefaultRenderer( NotificationEntry.class,
new StringTableRenderer());
notifTable.getSelectionModel().addListSelectionListener(
new ListSelectionListener()
{
public void valueChanged(ListSelectionEvent e)
{
if (!e.getValueIsAdjusting())
{
int row = notifTable.getSelectedRow();
if (row > -1)
{
configPanel.setNotificationEntry(
getNotificationEntry(row));
}
}
}
});
initTableData();
// Sort the table by description; otherwise, it looks chaotic.
if (columns.length != 0)
{
TableRowSorter<NotificationsTableModel> sorter
= new TableRowSorter<NotificationsTableModel>(model);
int column = columns.length - 1;
java.util.List<RowSorter.SortKey> sortKeys
= Arrays.asList(
new RowSorter.SortKey(
column,
SortOrder.ASCENDING));
sorter.setComparator(
column,
new Comparator<NotificationEntry>()
{
public int compare(
NotificationEntry ne1,
NotificationEntry ne2)
{
String s1
= Resources.getString(
"plugin.notificationconfig.event."
+ ne1.getEvent());
String s2
= Resources.getString(
"plugin.notificationconfig.event."
+ ne2.getEvent());
if (s1 == null)
return (s2 == null) ? 0 : -1;
else
return (s2 == null) ? 1 : s1.compareTo(s2);
}
});
sorter.setSortKeys(sortKeys);
notifTable.setRowSorter(sorter);
}
for(int i = 0; i < columns.length; i++)
{
TableColumn tmp = notifTable.getColumnModel().getColumn(i);
if(columns[i].getClass() != strTmp.getClass())
{
tmp.setHeaderRenderer(
new TableHeaderRenderer((JLabel)columns[i]));
tmp.setHeaderValue("");
}
else
{
tmp.setHeaderValue(columns[i]);
}
if(i < columns.length - 1)
{
tmp.setMaxWidth(25);
tmp.setMinWidth(25);
tmp.setPreferredWidth(25);
}
}
this.getViewport().add(notifTable);
}
/**
* Initializes table's data.
*/
private void initTableData()
{
for(String eventType : notificationService.getRegisteredEvents())
{
PopupMessageNotificationAction popupHandler
= (PopupMessageNotificationAction) notificationService
.getEventNotificationAction(
eventType, NotificationAction.ACTION_POPUP_MESSAGE);
CommandNotificationAction programHandler
= (CommandNotificationAction) notificationService
.getEventNotificationAction(
eventType, NotificationAction.ACTION_COMMAND);
SoundNotificationAction soundHandler
= (SoundNotificationAction) notificationService
.getEventNotificationAction(
eventType, NotificationAction.ACTION_SOUND);
NotificationEntry entry = new NotificationEntry(
notificationService.isActive(eventType),
programHandler != null && programHandler.isEnabled(),
(programHandler != null)
? programHandler.getDescriptor()
: null,
popupHandler != null
&& popupHandler.isEnabled(),
soundHandler != null
&& soundHandler.isEnabled()
&& soundHandler.isSoundNotificationEnabled(),
soundHandler != null
&& soundHandler.isEnabled()
&& soundHandler.isSoundPlaybackEnabled(),
soundHandler != null
&& soundHandler.isEnabled()
&& soundHandler.isSoundPCSpeakerEnabled(),
(soundHandler != null)
? soundHandler.getDescriptor()
: null,
eventType);
addEntry(entry);
}
}
/**
* Adds a line to the notifications table.
* @param entry the <tt>NotificationsTableEntry</tt> to add
*/
private void addEntry(NotificationEntry entry)
{
Object row[] = new Object[7];
row[0] = Boolean.valueOf(entry.getEnabled());
row[1] = (entry.getProgram()) ? ENABLED : DISABLED;
row[2] = entry.getPopup() ? ENABLED : DISABLED;
row[3] = (entry.getSoundNotification()) ? ENABLED : DISABLED;
row[4] = (entry.getSoundPlayback()) ? ENABLED : DISABLED;
row[5] = (entry.getSoundPCSpeaker()) ? ENABLED : DISABLED;
row[6] = entry;
this.addLine(row);
}
/**
* Adds a line to the notifications table.
* @param entry the <tt>NotificationsTableEntry</tt> to add
*/
private void setEntry(NotificationEntry entry)
{
int row = indexOfEntry(entry);
notifTable.setValueAt(new Boolean(entry.getEnabled()), row, 0);
notifTable.setValueAt((entry.getProgram()) ? ENABLED : DISABLED, row, 1);
notifTable.setValueAt(entry.getPopup() ? ENABLED : DISABLED, row, 2);
notifTable.setValueAt((entry.getSoundNotification())
? ENABLED : DISABLED, row, 3);
notifTable.setValueAt((entry.getSoundPlayback())
? ENABLED : DISABLED, row, 4);
notifTable.setValueAt((entry.getSoundPCSpeaker())
? ENABLED : DISABLED, row, 5);
notifTable.setValueAt(entry, row, 6);
}
/**
* Removes the row corresponding to the given <tt>entry</tt> from the table.
* @param entry the <tt>NotificationEntry</tt> to remove
*/
private void removeEntry(NotificationEntry entry)
{
int row = indexOfEntry(entry);
notifTable.removeRowSelectionInterval(row, row);
}
/**
* Adds a line to the notifications table.
* @param data the array of data to add
*/
private void addLine(Object data[])
{
if(data.length == model.getColumnCount())
model.addRow(data);
}
/**
* Returns the currently selected row.
* @return the currently selected row
*/
public int getSelectedRow()
{
return notifTable.getSelectedRow() ;
}
/**
* Returns the number of lines of the table.
* @return the number of lines of the table
*/
public int getRowCount()
{
return notifTable.getRowCount();
}
/**
* Selects the given row.
* @param row the row to select
*/
public void setSelectedRow(int row)
{
notifTable.setRowSelectionInterval(row, row);
}
/**
* Returns the notification entry at the given <tt>row</tt>.
* @param row the row number, which notification entry we're looking for
* @return the notification entry at the given <tt>row</tt>
*/
public NotificationEntry getNotificationEntry(int row)
{
return (NotificationEntry) notifTable
.getValueAt(row, notifTable.getColumnCount() - 1);
}
/**
* Returns the notification entry at the given <tt>row</tt>.
* @param eventName the name of the event, which corresponding
* <tt>NotificationEntry</tt> we're looking for
* @return the notification entry at the given <tt>row</tt>
*/
private NotificationEntry getNotificationEntry(String eventName)
{
for (int row = 0; row < notifTable.getRowCount(); row++)
{
NotificationEntry entry = getNotificationEntry(row);
if (entry.getEvent() == eventName)
return entry;
}
return null;
}
/**
* Adding a mouse listener on the table.
* @param l the <tt>MouseListener</tt> to add
*/
@Override
public void addMouseListener(MouseListener l)
{
notifTable.addMouseListener(l);
}
/**
* Returns the row number corresponding to the given <tt>point</tt>.
* @param point the point under which is the row we're looking for
* @return the row number corresponding to the given <tt>point</tt>
*/
public int rowAtPoint(Point point)
{
return notifTable.rowAtPoint(point);
}
/**
* Returns the row index of the given <tt>entry</tt>.
* @param entry the entry, which row we're looking for
* @return the row index of the given <tt>entry</tt>
*/
private int indexOfEntry(NotificationEntry entry)
{
for (int row = 0; row < notifTable.getRowCount(); row++)
{
NotificationEntry e = getNotificationEntry(row);
if (e.equals(entry))
return row;
}
return -1;
}
/**
* Returns the icon value of the given column if the the column supports an
* icon value, otherwise returns null.
* @param column the number of the column
* @return the icon value of the given column if the the column supports an
* icon value, otherwise returns null
*/
public static Icon getColumnIconValue(int column)
{
if(column == 1)
{
return new ImageIcon(Resources.getImageInBytes(
"plugin.notificationconfig.PROG_ICON"));
}
else if(column == 2)
{
return new ImageIcon(Resources.getImageInBytes(
"plugin.notificationconfig.POPUP_ICON"));
}
else if(column == 3)
{
return new ImageIcon(Resources.getImageInBytes(
"plugin.notificationconfig.SOUND_ICON_NOTIFY"));
}
else if(column == 4)
{
return new ImageIcon(Resources.getImageInBytes(
"plugin.notificationconfig.SOUND_ICON_PLAYBACK"));
}
else if(column == 5)
{
return new ImageIcon(Resources.getImageInBytes(
"plugin.notificationconfig.SOUND_ICON"));
}
return null;
}
/**
* Extends the JTable to make easier to use with this plug-in.
*/
static class NotificationTable extends JTable
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
private String[] columnToolTips;
/**
* Creates an instance of MyJTable.
* @param model the model of the table
*/
NotificationTable(TableModel model, String[] toolTips)
{
super(model);
this.columnToolTips = toolTips;
}
/**
* Creates the default table header.
* @return the table header
*/
@Override
protected JTableHeader createDefaultTableHeader()
{
return new JTableHeader(columnModel)
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
@Override
public String getToolTipText(MouseEvent e)
{
java.awt.Point p = e.getPoint();
int index = columnModel.getColumnIndexAtX(p.x);
int realIndex =
columnModel.getColumn(index).getModelIndex();
return Resources.getString(columnToolTips[realIndex]);
}
};
}
}
/**
* The data model used in the notifications table.
*/
private class NotificationsTableModel
extends DefaultTableModel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Creates an instance of <tt>NotificationsTableModel</tt>.
* @param columns the array of column names
* @param rowCount the number of rows
*/
NotificationsTableModel(Object[] columns, int rowCount)
{
super(columns, rowCount);
}
/**
* Returns the class of the given column.
* @param c the column number
* @return the class of the given column
*/
@Override
public Class<?> getColumnClass(int c)
{
return getValueAt(0, c).getClass();
}
@Override
public boolean isCellEditable(int row, int col)
{
if (col == 0)
return true;
return false;
}
}
/**
* Mouse listener that listens for clicks on image columns.
*/
private class NotificationsCellListener
extends MouseAdapter
{
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
* @param e the <tt>MouseEvent</tt> that notified us
*/
@Override
public void mouseClicked(MouseEvent e)
{
int row = notifTable.rowAtPoint(e.getPoint());
int col = notifTable.columnAtPoint(e.getPoint());
Object o = notifTable.getValueAt(row, col);
if (col > 0 && col < 6)
if (o.equals(ENABLED))
notifTable.setValueAt(DISABLED, row, col);
else
notifTable.setValueAt(ENABLED, row, col);
NotificationEntry entry = getNotificationEntry(row);
switch(col)
{
case 0:
boolean isActive
= notifTable.getValueAt(row, 0).equals(Boolean.TRUE);
entry.setEnabled(isActive);
notificationService.setActive(entry.getEvent(), isActive);
notifTable.repaint();
break;
case 1:
boolean isProgram
= notifTable.getValueAt(row, 1).equals(ENABLED);
entry.setProgram(isProgram);
if(isProgram)
{
notificationService.registerNotificationForEvent(
entry.getEvent(),
NotificationAction.ACTION_COMMAND,
entry.getProgramFile(),
"");
}
else
{
notificationService.removeEventNotificationAction(
entry.getEvent(),
NotificationAction.ACTION_COMMAND);
}
break;
case 2:
boolean isPopup = notifTable.getValueAt(row, 2).equals(ENABLED);
entry.setPopup(isPopup);
if(isPopup)
{
notificationService.registerNotificationForEvent(
entry.getEvent(),
NotificationAction.ACTION_POPUP_MESSAGE,
"",
"");
}
else
{
notificationService.removeEventNotificationAction(
entry.getEvent(),
NotificationAction.ACTION_POPUP_MESSAGE);
}
break;
case 3:
boolean isSoundNotification
= notifTable.getValueAt(row, 3).equals(ENABLED);
entry.setSoundNotification(isSoundNotification);
SoundNotificationAction soundNotificationAction
= (SoundNotificationAction)
notificationService.getEventNotificationAction(
entry.getEvent(), NotificationAction.ACTION_SOUND);
soundNotificationAction
.setSoundNotificationEnabled(isSoundNotification);
notificationService.registerNotificationForEvent(
entry.getEvent(),
soundNotificationAction);
break;
case 4:
boolean isSoundPlayback
= notifTable.getValueAt(row, 4).equals(ENABLED);
entry.setSoundPlayback(isSoundPlayback);
SoundNotificationAction soundPlaybackAction
= (SoundNotificationAction)
notificationService.getEventNotificationAction(
entry.getEvent(), NotificationAction.ACTION_SOUND);
soundPlaybackAction.setSoundPlaybackEnabled(isSoundPlayback);
notificationService.registerNotificationForEvent(
entry.getEvent(),
soundPlaybackAction);
break;
case 5:
boolean isPCSpeakerSound
= notifTable.getValueAt(row, 5).equals(ENABLED);
entry.setSoundPCSpeaker(isPCSpeakerSound);
SoundNotificationAction soundPCSpeakerAction
= (SoundNotificationAction)
notificationService.getEventNotificationAction(
entry.getEvent(), NotificationAction.ACTION_SOUND);
soundPCSpeakerAction.setSoundPCSpeakerEnabled(isPCSpeakerSound);
notificationService.registerNotificationForEvent(
entry.getEvent(),
soundPCSpeakerAction);
break;
};
configPanel.setNotificationEntry(entry);
}
}
/**
* Action Listener Service Notifications
* @param event the <tt>NotificationActionTypeEvent</tt> that notified us
*/
public void actionAdded(NotificationActionTypeEvent event)
{
String eventName = event.getSourceEventType();
NotificationEntry entry = getNotificationEntry(eventName);
NotificationAction handler = event.getActionHandler();
boolean isActionEnabled = (handler != null && handler.isEnabled());
if(entry == null)
{
entry = new NotificationEntry();
addEntry(entry);
}
entry.setEvent(eventName);
if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_POPUP_MESSAGE))
{
entry.setPopup(isActionEnabled);
}
else if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_COMMAND))
{
entry.setProgram(isActionEnabled);
entry.setProgramFile(((CommandNotificationAction)event
.getActionHandler()).getDescriptor());
}
else if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_SOUND))
{
entry.setSoundNotification(isActionEnabled);
entry.setSoundPlayback(isActionEnabled);
entry.setSoundFile(((SoundNotificationAction)event
.getActionHandler()).getDescriptor());
}
entry.setEnabled(notificationService.isActive(eventName));
setEntry(entry);
notifTable.repaint();
}
/**
* Action Listener Service Notifications
* @param event the <tt>NotificationActionTypeEvent</tt> that notified us
*/
public void actionRemoved(NotificationActionTypeEvent event)
{
String eventName = event.getSourceEventType();
NotificationEntry entry = getNotificationEntry(eventName);
if(entry == null)
return;
if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_POPUP_MESSAGE))
{
entry.setPopup(false);
}
else if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_COMMAND))
{
entry.setProgram(false);
entry.setProgramFile("");
}
else if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_SOUND))
{
entry.setSoundNotification(false);
entry.setSoundPlayback(false);
entry.setSoundPCSpeaker(false);
entry.setSoundFile("");
}
setEntry(entry);
notifTable.repaint();
}
/**
* Action Listener Service Notifications
* @param event the <tt>NotificationActionTypeEvent</tt> that notified us
*/
public void actionChanged(NotificationActionTypeEvent event)
{
String eventName = event.getSourceEventType();
NotificationEntry entry = getNotificationEntry(eventName);
if(entry == null)
return;
if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_COMMAND))
{
entry.setProgramFile(((CommandNotificationAction)event
.getActionHandler()).getDescriptor());
}
else if(event.getActionHandler().getActionType()
.equals(NotificationAction.ACTION_SOUND))
{
entry.setSoundFile(((SoundNotificationAction)event
.getActionHandler()).getDescriptor());
}
entry.setEnabled(notificationService.isActive(eventName));
setEntry(entry);
notifTable.repaint();
}
/**
* Adds the event to the notifications table.
* @param event the event to add
*/
public void eventTypeAdded(NotificationEventTypeEvent event)
{
String eventName = event.getSourceEventType();
NotificationEntry entry = getNotificationEntry(eventName);
if(entry == null)
{
PopupMessageNotificationAction popupHandler
= (PopupMessageNotificationAction) notificationService
.getEventNotificationAction(
eventName, NotificationAction.ACTION_POPUP_MESSAGE);
CommandNotificationAction programHandler
= (CommandNotificationAction) notificationService
.getEventNotificationAction(
eventName, NotificationAction.ACTION_COMMAND);
SoundNotificationAction soundHandler
= (SoundNotificationAction) notificationService
.getEventNotificationAction(
eventName, NotificationAction.ACTION_SOUND);
entry = new NotificationEntry(
notificationService.isActive(event.getSourceEventType()),
programHandler != null && programHandler.isEnabled(),
(programHandler != null) ? programHandler.getDescriptor() : null,
popupHandler != null && popupHandler.isEnabled(),
soundHandler != null && soundHandler.isSoundNotificationEnabled(),
soundHandler != null && soundHandler.isSoundPlaybackEnabled(),
soundHandler != null && soundHandler.isSoundPCSpeakerEnabled(),
(soundHandler != null) ? soundHandler.getDescriptor() : null,
eventName);
addEntry(entry);
notifTable.repaint();
}
}
/**
* Removes the event from the notifications table.
* @param event the event to remove
*/
public void eventTypeRemoved(NotificationEventTypeEvent event)
{
String eventName = event.getSourceEventType();
NotificationEntry entry = getNotificationEntry(eventName);
if(entry != null)
removeEntry(entry);
notifTable.repaint();
}
/**
* Clears the content of the notifications table.
*/
public void clear()
{
for(int numrows = model.getRowCount(), i = numrows - 1; i >=0; i--)
model.removeRow(i);
}
}