blob: f46ef13914939ded94faaec34c47ce1aff9f105f [file] [log] [blame]
/*
* Copyright (c) 2012, 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.examples.client.offline;
import org.eclipse.emf.cdo.examples.client.offline.FailoverMonitorView.OScope.Channel;
import org.eclipse.emf.cdo.server.net4j.FailoverMonitor;
import org.eclipse.emf.cdo.server.net4j.FailoverMonitor.AgentProtocol;
import org.eclipse.net4j.signal.SignalScheduledEvent;
import org.eclipse.net4j.util.container.ContainerEventAdapter;
import org.eclipse.net4j.util.container.IContainer;
import org.eclipse.net4j.util.container.IContainerEvent;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import java.io.ByteArrayInputStream;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* @author Eike Stepper
*/
public class FailoverMonitorView extends AbstractView<FailoverMonitor>
{
public static final String ID = "org.eclipse.emf.cdo.examples.client.offline.FailoverMonitorView"; //$NON-NLS-1$
public FailoverMonitorView()
{
super(FailoverMonitor.class);
}
@Override
protected void createPane(Composite parent, FailoverMonitor monitor)
{
final OScope scope = new OScope(parent, SWT.NONE);
monitor.addListener(new ContainerEventAdapter<AgentProtocol>()
{
@Override
protected void notifyContainerEvent(IContainerEvent<AgentProtocol> event)
{
addEvent(event);
super.notifyContainerEvent(event);
}
@Override
protected void onAdded(IContainer<AgentProtocol> monitor, final AgentProtocol agent)
{
final Channel channel = scope.getChannel(agent.getConnectorDescription());
agent.addListener(new IListener()
{
public void notifyEvent(IEvent event)
{
if (event instanceof SignalScheduledEvent)
{
if (!scope.isDisposed())
{
scope.getDisplay().asyncExec(new Runnable()
{
public void run()
{
if (!scope.isDisposed())
{
channel.peak();
}
}
});
}
}
}
});
}
});
}
@Override
public void setFocus()
{
}
/**
* @author Eike Stepper
*/
public static class OScope extends Canvas implements Runnable, PaintListener, ControlListener
{
public static final int[] PEAK = { 10, 95, 80, 90, 50, 25, 10, 5 };
private static final String INITIAL = "#INITIAL#";
private static final Random RANDOM = new Random();
private static final int[] BACKGROUND = { 255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, 72, 0, 72, 0, 0,
255, 254, 0, 19, 67, 114, 101, 97, 116, 101, 100, 32, 119, 105, 116, 104, 32, 71, 73, 77, 80, 255, 219, 0, 67,
0, 5, 3, 4, 4, 4, 3, 5, 4, 4, 4, 5, 5, 5, 6, 7, 12, 8, 7, 7, 7, 7, 15, 11, 11, 9, 12, 17, 15, 18, 18, 17, 15,
17, 17, 19, 22, 28, 23, 19, 20, 26, 21, 17, 17, 24, 33, 24, 26, 29, 29, 31, 31, 31, 19, 23, 34, 36, 34, 30, 36,
28, 30, 31, 30, 255, 219, 0, 67, 1, 5, 5, 5, 7, 6, 7, 14, 8, 8, 14, 30, 20, 17, 20, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 255, 192, 0, 17, 8, 0, 20, 0, 20, 3, 1, 34, 0, 2,
17, 1, 3, 17, 1, 255, 196, 0, 23, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 7, 255, 196, 0,
34, 16, 0, 2, 2, 0, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 4, 2, 20, 33, 52, 84, 17, 115, 145, 178, 209,
97, 255, 196, 0, 23, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 3, 255, 196, 0, 27, 17, 0, 2,
2, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 17, 33, 49, 81, 18, 255, 218, 0, 12, 3, 1, 0, 2, 17, 3, 17,
0, 63, 0, 225, 37, 87, 118, 245, 59, 79, 217, 140, 212, 60, 24, 60, 226, 250, 83, 110, 196, 74, 10, 205, 211,
133, 245, 141, 180, 155, 122, 106, 255, 0, 78, 77, 187, 88, 4, 164, 237, 96, 204, 5, 89, 168, 120, 48, 121, 197,
244, 10, 223, 5, 233, 240, 148, 170, 238, 222, 167, 105, 251, 48, 9, 237, 20, 182, 137, 64, 6, 140, 255, 217 };
private SortedMap<String, Channel> channels = new TreeMap<String, Channel>();
private Channel[] channelArray;
private int width;
private int height;
private int channelHeight;
private boolean resizing;
private Color black;
private Color white;
public OScope(Composite parent, int style)
{
super(parent, style | SWT.DOUBLE_BUFFERED);
black = getDisplay().getSystemColor(SWT.COLOR_BLACK);
white = getDisplay().getSystemColor(SWT.COLOR_WHITE);
setBackgroundImage(createBackgroundImage());
addPaintListener(this);
addControlListener(this);
Channel channel = new Channel(INITIAL);
channels.put(INITIAL, channel);
channelArray = new Channel[] { channel };
run();
}
public int getTimerExecMillis()
{
return 25;
}
@Override
public void dispose()
{
super.dispose();
}
public Channel getChannel(String name)
{
synchronized (channels)
{
Channel channel = channels.get(name);
if (channel == null)
{
boolean resize = false;
channel = channels.remove(INITIAL);
if (channel == null)
{
channel = new Channel(name);
resize = true;
}
else
{
channel.setName(name);
}
channels.put(name, channel);
channelArray = channels.values().toArray(new Channel[channels.size()]);
if (resize)
{
getDisplay().syncExec(new Runnable()
{
public void run()
{
controlResized(null);
}
});
}
}
return channel;
}
}
public void controlMoved(ControlEvent e)
{
// Do nothing
}
public void controlResized(ControlEvent e)
{
try
{
resizing = true;
Point size = getSize();
width = size.x;
height = size.y;
int count = channelArray.length;
if (count == 0)
{
return;
}
int oldChannelHeight = channelHeight;
if (oldChannelHeight == 0)
{
oldChannelHeight = 1;
}
channelHeight = height / (2 * count);
int y = channelHeight;
for (Channel channel : channelArray)
{
channel.resize(y, oldChannelHeight);
y += channelHeight + channelHeight;
}
}
finally
{
resizing = false;
}
}
public void paintControl(PaintEvent e)
{
if (!resizing)
{
GC gc = e.gc;
gc.setAdvanced(true);
gc.setAntialias(SWT.ON);
for (Channel channel : channelArray)
{
channel.paint(e.gc);
}
}
}
public void run()
{
if (isDisposed())
{
return;
}
redraw();
getDisplay().timerExec(getTimerExecMillis(), this);
}
protected Image createBackgroundImage()
{
byte[] bytes = new byte[BACKGROUND.length];
for (int i = 0; i < BACKGROUND.length; i++)
{
bytes[i] = (byte)BACKGROUND[i];
}
return new Image(getDisplay(), new ByteArrayInputStream(bytes));
}
/**
* @author Eike Stepper
*/
public class Channel
{
private String name;
private int[] values;
private int[] head;
private int headIndex;
private boolean headNegate;
private int x;
private int y;
public Channel(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setHead(int[] head)
{
headIndex = 0;
headNegate = false;
this.head = head;
}
public void peak()
{
setHead(PEAK);
}
@Override
public String toString()
{
return "Channel[" + name + "]";
}
public void resize(int y, int oldChannelHeight)
{
int max = 0;
int[] newValues = new int[2 * width];
if (values != null)
{
System.arraycopy(values, 0, newValues, 0, Math.min(values.length, newValues.length));
max = Math.min(values.length / 2, width);
}
int x = 0;
for (; x < max; x++)
{
int i = 2 * x;
newValues[i] = x;
newValues[i + 1] = (newValues[i + 1] - this.y) * channelHeight / oldChannelHeight + y;
}
for (; x < width; x++)
{
int i = 2 * x;
newValues[i] = x;
newValues[i + 1] = y;
}
values = newValues;
x = Math.min(x, width);
this.y = y;
}
public void paint(GC gc)
{
int i = 2 * x + 1;
if (values == null || i >= values.length)
{
return;
}
int value = getNextValue() * (90 + RANDOM.nextInt(20)) / 100 + RANDOM.nextInt(4) - 2;
if (value > 100)
{
value = 100;
}
else if (value < -100)
{
value = -100;
}
int fx = y + value * channelHeight / 100;
values[i] = fx;
gc.setForeground(white);
gc.setLineWidth(1);
gc.drawPolyline(values);
gc.setForeground(black);
gc.setLineWidth(2);
gc.drawRectangle(x, fx, 2, 2);
if (++x >= width)
{
x = 0;
}
}
void setName(String name)
{
this.name = name;
}
private int getNextValue()
{
if (head == null)
{
return 0;
}
int value;
if (headNegate)
{
value = -head[headIndex];
if (++headIndex >= head.length)
{
setHead(null);
headNegate = !headNegate;
}
}
else
{
value = head[headIndex];
}
headNegate = !headNegate;
return value;
}
}
}
}