package pctelelog.ui.notify;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Resource;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import pctelelog.ContactInfo.Name;
import pctelelog.ContactInfo.Photo;
import pctelelog.events.AbstractCallEvent;
import pctelelog.ui.PreferenceKey;
import pctelelog.ui.PreferenceManager;
import pctelelog.ui.WindowWidget;
public class EventWindow implements WindowWidget, DisposeListener {
private static final int SMALL_WIDTH = 150;
private static final int SMALL_HEIGHT = 50;
private static final int LARGE_WIDTH = SMALL_WIDTH * 2;
private static final int LARGE_HEIGHT = SMALL_HEIGHT * 3;
/**
* Padding from screen edge
*/
private static final int PADDING = 50;
/**
* Resources to be disposed of
* at shell disposal
*/
private ArrayList<Resource> m_resources = new ArrayList<Resource>();
private final Display m_display;
private final Shell m_windowShell;
private boolean m_isDetailed = false;
private WindowLocation m_windowLocation = null;
private boolean m_autoDispose = true;
public EventWindow(final Display display, boolean isDetailed) {
if(display == null) { throw new NullPointerException("Display cannot be null."); }
m_display = display;
m_windowShell = new Shell(m_display, SWT.NO_TRIM | SWT.TOOL | SWT.ON_TOP);
m_isDetailed = isDetailed;
// Register resource reclamation
m_windowShell.addDisposeListener(this);
// Add Mouse Listener for clicks
getWindowShell().addMouseListener(new MouseListener() {
public void mouseUp(MouseEvent e) {
disableAutoClose();
}
public void mouseDown(MouseEvent e) {}
public void mouseDoubleClick(MouseEvent e) {}
});
}
/** Event Actions **/
public static EventWindow connect(Display display) {
EventWindow eventWindow = new EventWindow(display, false);
//Set size and location
WindowLocation loc = eventWindow.pollWindowLocation();
eventWindow.setWindowSizeAndLocation(loc);
// Create status label
Label text = new Label(eventWindow.getWindowShell(), SWT.HORIZONTAL);
text.setText("Phone Connected");
return eventWindow;
}
/**
* Create an event window for a call type event
* @param display the main display loop
* @param event the event to show
* @return an instantiated EventWindow
*/
public static EventWindow call(Display display, AbstractCallEvent event) {
EventWindow eventWindow = new EventWindow(display , true);
// Set size and location
WindowLocation loc = eventWindow.pollWindowLocation();
eventWindow.setWindowSizeAndLocation(loc);
eventWindow.createDetailedLayout(event, eventWindow);
return eventWindow;
}
public Shell getWindowShell() {
return m_windowShell;
}
public Display getMainDisplay() {
return m_display;
}
public WindowLocation getWindowLocation() {
return m_windowLocation;
}
public void open() {
getWindowShell().open();
}
public void disableAutoClose() {
m_autoDispose = false;
}
public void closeAfterEffect() {
if(m_autoDispose) {
getWindowShell().dispose();
}
else {
createCloseLabel();
}
}
public void registerResource(Resource rs) {
if(rs == null) { throw new NullPointerException("Resource cannot be null."); }
m_resources.add(rs);
}
public void widgetDisposed(DisposeEvent e) {
for(Resource rs: m_resources) {
if(!rs.isDisposed()) {
rs.dispose();
}
}
}
/**
* Retrieve the Event Window Effect from
* preferences
*
* @return the current Event Window Effect
*/
public EventWindowEffect getEffect() {
@SuppressWarnings("unchecked")
Class<? extends EventWindowEffect> effectClass = (Class<? extends EventWindowEffect>) PreferenceManager.getPreferenceManager()
.get(PreferenceKey.EFFECT_TYPE, StandardShowEffect.class);
EventWindowEffect out = null;
try {
out = effectClass.getConstructor(EventWindow.class).newInstance(this);
} catch(Exception e) {
e.printStackTrace();
}
return out;
}
/**
* Is the event window a detailed event
*
* @return true if it is, false if it isn't
*/
private boolean isDetailed() {
return m_isDetailed;
}
/**
* Retrieve Event Window display location from
* preferences
*
* @return the enum location
*/
private WindowLocation pollWindowLocation() {
return (WindowLocation) PreferenceManager.getPreferenceManager()
.get(PreferenceKey.WINDOW_LOCATION, WindowLocation.BOTTOM_RIGHT);
}
/**
* Get a rectangle that specifies where the event
* window should be displayed.
*
* @param loc the window location area
* @param edgePadding the padding between the windo and the screen edge
* @param isDetails is the event window a detailed event (Incoming/Missed call)
* @return a rectangle with the size and location set
*/
private Rectangle getShellSizeAndLocation(WindowLocation loc, int edgePadding, boolean isDetails) {
if(loc == null) { throw new NullPointerException("Location cannot be null."); }
Rectangle monitorRegion = getMainDisplay().getPrimaryMonitor().getClientArea();
int monitorWidth = monitorRegion.width;
int monitorHeight = monitorRegion.height;
int width = isDetails ? LARGE_WIDTH : SMALL_WIDTH;
int height = isDetails ? LARGE_HEIGHT: SMALL_HEIGHT;
int x = edgePadding;
int y = edgePadding;
switch(loc) {
case BOTTOM_LEFT:
y = monitorHeight - (y + height);
break;
case BOTTOM_RIGHT:
x = monitorWidth - (x + width);
y = monitorHeight - (y + height);
break;
case TOP_LEFT:
break;
case TOP_RIGHT:
x = monitorWidth - (x + width);
break;
}
return new Rectangle(x, y, width, height);
}
/**
* Set the current Event Window's location
* to the Window Location region
*
* @param location the region the window should be displayed at
*/
private void setWindowSizeAndLocation(WindowLocation location) {
Rectangle loc = getShellSizeAndLocation(location, PADDING , isDetailed());
getWindowShell().setSize(loc.width, loc.height);
getWindowShell().setLocation(loc.x, loc.y);
m_windowLocation = location;
}
/**
* Event Window Control item creation methods
*/
private void createDetailedLayout(AbstractCallEvent event, EventWindow window) {
// Setup layout
GridLayout layout = new GridLayout(3, true);
getWindowShell().setLayout(layout);
createNotifyLabel(event, window);
createPhotoLabel(event, window);
createNameLabel(event, window);
createNumberLabel(event, window);
createEmailLabel(event, window);
createDeviceLabel(event,window);
registerShellAutoDisposeAbort();
}
private void createNotifyLabel(AbstractCallEvent event, EventWindow window) {
Label typeLabel = new Label(window.getWindowShell(), SWT.CENTER);
typeLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER | SWT.TOP, true, true, 3, 1));
typeLabel.setFont(new Font(window.getMainDisplay(),"Arial",12, SWT.BOLD));
switch(event.getEventType()) {
case INCOMING_CALL:
typeLabel.setText("INCOMING CALL");
break;
case MISSED_CALL:
typeLabel.setText("MISSED CALL");
break;
default:
typeLabel.setText("UNKNOWN EVENT: " + event.getEventType().toString());
break;
}
}
private boolean createPhotoLabel(AbstractCallEvent event, EventWindow window) {
Photo photo = event.getContactInfo().getPhoto();
Image img = null;
if(photo == null) {
ClassLoader loader = EventHandler.class.getClassLoader();
InputStream dataStream = loader.getResourceAsStream("nophoto.png");
try {
img = (dataStream == null) ? null : new Image(window.getMainDisplay(), dataStream);
} catch(SWTException e) {
img = null;
}
}
else {
ByteArrayInputStream data = new ByteArrayInputStream(photo.getDecodedData());
img = new Image(window.getMainDisplay(), data);
}
Label imgLabel = new Label(window.getWindowShell(), SWT.CENTER);
if(img == null) {
imgLabel.setText("No Photo");
imgLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 3));
}
else {
// Resize for column
int colWidth = window.getWindowShell().getBounds().width / 3;
int colHeight = (int)(window.getWindowShell().getBounds().height * .75);
img = scaleImage(img, colWidth, colHeight);
window.registerResource(img);
imgLabel.setImage(img);
imgLabel.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true, 1, 3));
}
return true;
}
private void createNameLabel(AbstractCallEvent event, EventWindow window) {
Label nameLabel = new Label(window.getWindowShell(), SWT.CENTER);
Name name_data = event.getContactInfo().getName();
String name = name_data.getDisplayName().equals("") ?
name_data.getFirst() + " " + name_data.getLast() : name_data.getDisplayName();
nameLabel.setText(name);
nameLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1));
}
private void createNumberLabel(AbstractCallEvent event, EventWindow window) {
Label numberLabel = new Label(window.getWindowShell(), SWT.CENTER);
numberLabel.setText(event.getContactInfo().getNumber().getNumber());
numberLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1));
}
private void createEmailLabel(AbstractCallEvent event, EventWindow window) {
Label emailLabel = new Label(window.getWindowShell(), SWT.LEFT);
emailLabel.setText(event.getContactInfo().getEmail().getEmail());
emailLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1));
}
private void createDeviceLabel(AbstractCallEvent event, EventWindow window) {
Label deviceLabel = new Label(window.getWindowShell(), SWT.LEFT);
deviceLabel.setText(event.getDevice().getName());
deviceLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1));
}
private void createCloseLabel() {
int labelSize = 25;
Button closeLabel = new Button(getWindowShell(), SWT.PUSH);
closeLabel.setText("close");
closeLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 3, 1));
closeLabel.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
getWindowShell().close();
}
});
Rectangle bounds = getWindowShell().getBounds();
getWindowShell().setBounds(bounds.x, bounds.y-labelSize, bounds.width, bounds.height+labelSize);
}
/**
* Scale an image to a width and height
* <p>
* Old image will be disposed of and a new image returned.
*
* @param image image to be scaled
* @param width the width of the new image
* @param height the height of the new image
* @return a new image scaled
*/
private Image scaleImage(Image image, int width, int height) {
Image scaled = new Image(getMainDisplay(), width, height);
GC gc = new GC(scaled);
gc.setAntialias(SWT.ON);
gc.setInterpolation(SWT.HIGH);
gc.drawImage(image, 0, 0, image.getBounds().width, image.getBounds().height, 0, 0, width, height);
gc.dispose();
image.dispose();
return scaled;
}
/**
* Register all of the shell's children controls
* for mouse events so that on click they will trigger
* the auto dispose to abort
*/
private void registerShellAutoDisposeAbort() {
Control[] controls = getWindowShell().getChildren();
for(Control control : controls) {
control.addMouseListener(new MouseListener() {
public void mouseUp(MouseEvent e) {
disableAutoClose();
}
public void mouseDown(MouseEvent e) {}
public void mouseDoubleClick(MouseEvent e) {}
});
}
}
}