/*
* Created on Apr 30, 2007
* Created by Paul Gardner
* Copyright (C) 2007 Aelitis, All Rights Reserved.
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 63.529,40 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.ui.swt.speedtest;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AEThread;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.DisplayFormatters;
import org.gudy.azureus2.ui.swt.wizard.AbstractWizardPanel;
import org.gudy.azureus2.ui.swt.wizard.IWizardPanel;
import org.gudy.azureus2.ui.swt.wizard.WizardListener;
import org.gudy.azureus2.ui.swt.Messages;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.mainwindow.Cursors;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminSpeedTestScheduledTest;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminSpeedTestScheduledTestListener;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminSpeedTesterListener;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminSpeedTestScheduler;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminSpeedTester;
import com.aelitis.azureus.core.networkmanager.admin.NetworkAdminSpeedTesterResult;
import com.aelitis.azureus.core.networkmanager.admin.impl.NetworkAdminSpeedTestSchedulerImpl;
public class
SpeedTestPanel
extends AbstractWizardPanel
implements NetworkAdminSpeedTestScheduledTestListener, NetworkAdminSpeedTesterListener
{
private NetworkAdminSpeedTestScheduler nasts;
private NetworkAdminSpeedTestScheduledTest scheduled_test;
private Combo testCombo;
private Button encryptToggle;
private Color originalColor;
private Button test;
private Button abort;
private Label testCountDown1;
private Label testCountDown2;
private Text textMessages;
private ProgressBar progress;
private Display display;
private boolean test_running;
private boolean switched_to_close;
//measured upload and download results.
int uploadTest, downloadTest;
long maxUploadTest, maxDownloadTest;
WizardListener clListener;
private static final String START_VALUES = " - ";
public
SpeedTestPanel(
SpeedTestWizard _wizard,
IWizardPanel _previousPanel)
{
super( _wizard, _previousPanel );
wizard = _wizard;
nasts = NetworkAdminSpeedTestSchedulerImpl.getInstance();
}
public void
show()
{
display = wizard.getDisplay();
wizard.setTitle(MessageText.getString( SpeedTestWizard.CFG_PREFIX + "run" ));
wizard.setCurrentInfo( MessageText.getString("SpeedTestWizard.test.panel.currinfo") );
wizard.setPreviousEnabled(false);
wizard.setFinishEnabled(false);
Composite rootPanel = wizard.getPanel();
GridLayout layout = new GridLayout();
layout.numColumns = 1;
rootPanel.setLayout(layout);
Composite panel = new Composite(rootPanel, SWT.NULL);
GridData gridData = new GridData(GridData.FILL_BOTH);
panel.setLayoutData(gridData);
/////////////////////////////////////////
//Add group to link to Azureus Wiki page.
/////////////////////////////////////////
Group azWiki = new Group(panel, SWT.WRAP);
GridData azwGridData = new GridData();
azwGridData.widthHint = 350;
azwGridData.horizontalSpan = 4;
azWiki.setLayoutData(azwGridData);
GridLayout azwLayout = new GridLayout();
azwLayout.numColumns = 1;
//azwLayout.marginHeight = 1;
azWiki.setLayout(azwLayout);
azWiki.setText(MessageText.getString("Utils.link.visit"));
final Label linkLabel = new Label(azWiki, SWT.NULL);
linkLabel.setText( "Azureus Wiki Speed Test" );
linkLabel.setData("http://azureus.aelitis.com/wiki/index.php/Speed_Test_FAQ");
linkLabel.setCursor(Cursors.handCursor);
linkLabel.setForeground(Colors.blue);
azwGridData = new GridData();
azwGridData.horizontalIndent = 10;
linkLabel.setLayoutData( azwGridData );
linkLabel.addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent arg0) {
Utils.launch((String) ((Label) arg0.widget).getData());
}
public void mouseUp(MouseEvent arg0) {
Utils.launch((String) ((Label) arg0.widget).getData());
}
});
//space line
Label spacer = new Label(panel, SWT.NULL);
gridData = new GridData();
gridData.horizontalSpan = 4;
spacer.setLayoutData(gridData);
//label explain section.
layout = new GridLayout();
layout.numColumns = 4;
panel.setLayout(layout);
Label explain = new Label(panel, SWT.WRAP);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 4;
explain.setLayoutData(gridData);
Messages.setLanguageText(explain,"SpeedTestWizard.test.panel.explain");
//space line
spacer = new Label(panel, SWT.NULL);
gridData = new GridData();
gridData.horizontalSpan = 4;
spacer.setLayoutData(gridData);
//label type and button section.
Label ul = new Label(panel, SWT.NULL );
gridData = new GridData();
ul.setLayoutData(gridData);
Messages.setLanguageText(ul,"SpeedTestWizard.test.panel.label");
testCombo = new Combo(panel, SWT.READ_ONLY);
gridData = new GridData(GridData.FILL_HORIZONTAL);
testCombo.setLayoutData(gridData);
int[] test_types = NetworkAdminSpeedTester.TEST_TYPES;
int up_only_index = 0;
for (int i=0;i<test_types.length;i++){
int test_type = test_types[i];
String resource = null;
if ( test_type == NetworkAdminSpeedTester.TEST_TYPE_UPLOAD_ONLY ){
resource = "up";
up_only_index = i;
}else if ( test_type == NetworkAdminSpeedTester.TEST_TYPE_DOWNLOAD_ONLY ){
resource = "down";
}else{
Debug.out( "Unknown test type" );
}
//List all test in drop-down.
testCombo.add( "BT " + MessageText.getString( "speedtest.wizard.test.mode." + resource ), i);
}
testCombo.select( up_only_index );
test = new Button(panel, SWT.PUSH);
Messages.setLanguageText(test,"dht.execute");//Run
gridData = new GridData();
gridData.widthHint = 70;
test.setLayoutData(gridData);
test.addListener(SWT.Selection, new RunButtonListener() );
abort = new Button(panel, SWT.PUSH);
Messages.setLanguageText(abort,"SpeedTestWizard.test.panel.abort");//Abort
gridData = new GridData();
gridData.widthHint = 70;
abort.setLayoutData(gridData);
abort.setEnabled(false);
abort.addListener(SWT.Selection, new AbortButtonListener() );
//toggle button line.
Label enc = new Label( panel, SWT.NULL );
gridData = new GridData();
enc.setLayoutData(gridData);
Messages.setLanguageText(enc,"SpeedTestWizard.test.panel.enc.label");
encryptToggle = new Button(panel, SWT.TOGGLE);
String statusString="SpeedTestWizard.test.panel.standard";
if( encryptToggle.getSelection() ){
statusString = "SpeedTestWizard.test.panel.encrypted";
}
Messages.setLanguageText(encryptToggle,statusString);
gridData = new GridData();
gridData.widthHint = 80;
encryptToggle.setLayoutData(gridData);
encryptToggle.addListener(SWT.Selection, new EncryptToggleButtonListener() );
//finish line
Label spacer2 = new Label(panel, SWT.NULL);
gridData = new GridData();
gridData.horizontalSpan = 2;
spacer2.setLayoutData(gridData);
//test count down section.
Label abortCountDown = new Label(panel, SWT.NULL);
gridData = new GridData();
abortCountDown.setLayoutData(gridData);
Messages.setLanguageText(abortCountDown,"SpeedTestWizard.test.panel.abort.countdown");
testCountDown1 = new Label(panel, SWT.NULL);
gridData = new GridData();
testCountDown1.setLayoutData(gridData);
testCountDown1.setText(START_VALUES);
Label testFinishCountDown = new Label(panel, SWT.NULL);
gridData = new GridData();
testFinishCountDown.setLayoutData(gridData);
Messages.setLanguageText(testFinishCountDown,"SpeedTestWizard.test.panel.test.countdown");
testCountDown2 = new Label(panel, SWT.NULL);
gridData = new GridData();
testCountDown2.setLayoutData(gridData);
testCountDown2.setText(START_VALUES);
//progress bar section.
progress = new ProgressBar(panel, SWT.SMOOTH);
progress.setMinimum(0);
progress.setMaximum(100);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 4;
progress.setLayoutData(gridData);
//message text section.
textMessages = new Text(panel, SWT.BORDER | SWT.MULTI | SWT.READ_ONLY | SWT.V_SCROLL | SWT.H_SCROLL );
textMessages.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
gridData = new GridData(GridData.FILL_BOTH);
gridData.horizontalSpan = 4;
gridData.heightHint = 60;
textMessages.setLayoutData(gridData);
//this should only be new when returning from a previous panel.
String lastData = SpeedTestData.getInstance().getLastTestData();
if(lastData!=null){
textMessages.setText(lastData);
}
}
public void
finish()
{
test_running = true;
clListener = new WizardListener()
{
public void
closed()
{
cancel();
}
};
wizard.addListener(clListener);
wizard.setFinishEnabled( false );
// convert to mode
final int test_mode = NetworkAdminSpeedTester.TEST_TYPES[testCombo.getSelectionIndex()];
final boolean encState = encryptToggle.getSelection();
Thread t =
new AEThread("SpeedTest Performer")
{
public void
runSupport()
{
runTest(test_mode, encState);
}
};
t.setPriority(Thread.MIN_PRIORITY);
t.setDaemon(true);
t.start();
}
public void
cancel()
{
if ( scheduled_test != null ){
scheduled_test.abort();
if ( !test.isDisposed()){
test.setEnabled(true);
abort.setEnabled(false);
wizard.setNextEnabled(false);
wizard.setFinishEnabled(false);
}
}
}
protected void
runTest( int test_mode, boolean encrypt_mode )
{
test_running = true;
if ( nasts.getCurrentTest() != null ){
reportStage( MessageText.getString("SpeedTestWizard.test.panel.already.running") );
}else{
// what's the contract here in terms of listener removal?
try{
reportStage( MessageText.getString("SpeedTestWizard.stage.message.requesting") );
scheduled_test = nasts.scheduleTest( NetworkAdminSpeedTestScheduler.TEST_TYPE_BT );
scheduled_test.getTester().setMode( test_mode );
scheduled_test.getTester().setUseCrypto( encrypt_mode );
scheduled_test.addListener( this );
scheduled_test.getTester().addListener( this );
maxUploadTest = scheduled_test.getMaxUpBytePerSec();
maxDownloadTest = scheduled_test.getMaxDownBytePerSec();
scheduled_test.start();
}catch( Throwable e ){
String requestNotAccepted = MessageText.getString("SpeedTestWizard.test.panel.not.accepted");
reportStage( requestNotAccepted + Debug.getNestedExceptionMessage(e));
if (!test.isDisposed()) {
display.asyncExec(new AERunnable(){
public void runSupport() {
test.setEnabled(true);
abort.setEnabled(false);
encryptToggle.setEnabled(true);
}
});
}
}
}//else
}//runTest
public void
stage(
NetworkAdminSpeedTestScheduledTest test,
String step )
{
reportStage( step );
}
public void
complete(
NetworkAdminSpeedTestScheduledTest test )
{
}
public void
stage(
NetworkAdminSpeedTester tester,
String step )
{
reportStage( step );
}
public void
complete(
NetworkAdminSpeedTester tester,
NetworkAdminSpeedTesterResult result )
{
SpeedTestData.getInstance().setResult( result );
reportComplete( result );
}
protected void
reportComplete(
final NetworkAdminSpeedTesterResult result )
{
if ( !textMessages.isDisposed()) {
display.asyncExec(new AERunnable(){
public void runSupport() {
if ( !textMessages.isDisposed()){
if ( result.hadError()){
String testFailed = MessageText.getString("SpeedTestWizard.test.panel.testfailed");//Test failed
textMessages.append( testFailed+": " + result.getLastError());
test.setEnabled( true );
abort.setEnabled(false);
encryptToggle.setEnabled(true);
wizard.setErrorMessage(testFailed);
}else{
uploadTest = result.getUploadSpeed();
downloadTest = result.getDownloadSpeed();
String uploadSpeedStr = MessageText.getString("GeneralView.label.uploadspeed");
String downlaodSpeedStr = MessageText.getString("GeneralView.label.downloadspeed");
textMessages.append(uploadSpeedStr+" " + DisplayFormatters.formatByteCountToKiBEtcPerSec(result.getUploadSpeed()) + Text.DELIMITER);
textMessages.append(downlaodSpeedStr+" " + DisplayFormatters.formatByteCountToKiBEtcPerSec(result.getDownloadSpeed()) + Text.DELIMITER);
wizard.setNextEnabled(true);
abort.setEnabled(false);
test.setEnabled(true);
encryptToggle.setEnabled(true);
}
if( !result.hadError() ){
switchToClose();
}
}
}
});
}
wizard.removeListener(clListener);
clListener=null;
}
protected void
reportStage(
final String step )
{
if ( !textMessages.isDisposed()) {
display.asyncExec(new AERunnable(){
public void runSupport() {
if ( !textMessages.isDisposed()){
if(step==null)
return;
//intercept progress indications.
if( step.startsWith("progress:")){
//expect format of string to be "progress: # : ..." where # is 0-100
int progressAmount = getProgressBarValueFromString(step);
progress.setSelection(progressAmount);
int[] timeLeft = getTimeLeftFromString(step);
if(timeLeft!=null){
//ToDo: use SimpleDateFormat ... to internationalize this.
testCountDown1.setText( ""+timeLeft[0]+" sec " );//
testCountDown2.setText( ""+timeLeft[1]+" sec " );
}else{
testCountDown1.setText(START_VALUES);
testCountDown2.setText(START_VALUES);
}
String modified = modifyProgressStatusString(step);
textMessages.append(modified);
}else{
//print non-progress strings as is.
textMessages.append( step + Text.DELIMITER);
}
}
}
});
}
}
/**
* Change the "progress status" string into something that can be displayed.
* @param step - String must start with "progress:"
* @return - a String that can be displayed in the Text Messages window.
*/
private static String modifyProgressStatusString(String step){
if(step==null){
return " ";
}
if( !step.startsWith("progress:") ){
return " ";
}
String[] values = step.split(":");
//the expected format is:
// progress: 87 : download ave 0 : upload ave 512438 : 93 : 3
//values[2] should be download ave
//values[3] should be upload ave
if(values.length<4){
return " ";
}
int downAve = getValueFromAveString(values[2]);
int upAve = getValueFromAveString(values[3]);
//ToDo: If an upload test then do only an upload. If a download test, then do only a download.
//ToDo: need something that informs what the test type is.
StringBuffer sb = new StringBuffer();
sb.append(MessageText.getString("GeneralView.label.uploadspeed"));
sb.append( DisplayFormatters.formatByteCountToKiBEtcPerSec( upAve ) ).append(" , ");
sb.append(MessageText.getString("GeneralView.label.downloadspeed"));
sb.append( DisplayFormatters.formatByteCountToKiBEtcPerSec( downAve) );
sb.append("\n");
return sb.toString();
}
/**
* Get the number after the last " " space in the String.
* @param aveStr - String in format "download ave 32000"
* @return int 32000, or -1 if an error.
*/
private static int getValueFromAveString(String aveStr){
try{
int number=-2;
aveStr = aveStr.trim();
String[] parts = aveStr.split(" ");
//the last item should be the number.
if(parts!=null){
number = Integer.parseInt( parts[parts.length-1].trim() );
}
return number;
}catch(Throwable t){
return -1;
}
}//getValueFromAveString
/**
* If you find the time left values then use them. On any error return null and the calling
* function should handle that condition.
* @param step - String in format "progress: #: text: text: #: #" The last two items are
* the seconds till abort and seconds till complete respectively.
* @return - int array of size 2 with time left in test, or null on any error.
*/
private static int[] getTimeLeftFromString(String step){
if(step==null)
return null;
if( !step.startsWith("progress:") )
return null;
String[] values = step.split(":");
if(values.length<5){
return null;
}
int[] times = new int[2];
try{
times[0] = Integer.parseInt( values[4].trim() );
times[1] = Integer.parseInt( values[5].trim() );
//don't allow time values less then zero.
if(times[0]<0){
times[0]=0;
}
if(times[1]<0){
times[1]=0;
}
}catch(Exception e){
return null;
}
return times;
}//getTimeLeftFromString
/**
*
* @param step - String with the expected format. "progress: #" where # is 0 - 100.
* @return The number as an integer, if the result is not known return 0.
*/
private static int getProgressBarValueFromString(String step){
if(step==null)
return 0;
if( !step.startsWith("progress:") )
return 0;
String[] value = step.split(":");
if(value.length<2)
return 0;
int progress;
try{
progress = Integer.parseInt(value[1].trim());
}catch(Exception e){
return 0;
}
if( progress<0 || progress>100 )
return 0;
return progress;
}//getProgressValueFromString
protected void
switchToClose()
{
switched_to_close = true;
wizard.switchToClose();
}
public boolean
isFinishEnabled()
{
return( !( switched_to_close || test_running ));
}
public boolean
isFinishSelectionOK()
{
return( !( switched_to_close || test_running ));
}
public IWizardPanel
getFinishPanel()
{
return( this );
}
public boolean isNextEnabled(){
//only enable after the test completes correctly.
return ( (uploadTest>0 || downloadTest>0) && !test_running);
}//isNextEnabled
public IWizardPanel getNextPanel() {
SpeedTestData persist = SpeedTestData.getInstance();
persist.setLastTestData( textMessages.getText() );
return new SpeedTestSetLimitPanel( wizard, this, uploadTest, maxUploadTest, downloadTest, maxDownloadTest);
}
/**
* An abort button listener
*/
class AbortButtonListener implements Listener{
public void handleEvent(Event event) {
//same action as "cancel" button.
cancel();
test.setEnabled(true);
abort.setEnabled(false);
encryptToggle.setEnabled(true);
wizard.setNextEnabled(false);
uploadTest=0;
downloadTest=0;
String testAbortedManually = MessageText.getString("SpeedTestWizard.test.panel.aborted");
wizard.setErrorMessage(testAbortedManually);
reportStage("\n"+testAbortedManually);
}//handleEvent
}
/**
* A run button listener
*/
class RunButtonListener implements Listener{
public void handleEvent(Event event) {
abort.setEnabled(true);
test.setEnabled(false);
encryptToggle.setEnabled(false);
wizard.setErrorMessage("");
wizard.setNextEnabled(false);
textMessages.setText("");
finish();
}//handleEvent
}
/**
* Run test with encryption toggle button listener.
*/
class EncryptToggleButtonListener implements Listener{
public void handleEvent(Event event){
if(encryptToggle.getSelection()){
Messages.setLanguageText(encryptToggle,"SpeedTestWizard.test.panel.encrypted");
originalColor = encryptToggle.getForeground();
//Color highlightColor = ColorCache.getColor(display,178,78,127);
Color highlightColor = display.getSystemColor(SWT.COLOR_DARK_YELLOW);
encryptToggle.setBackground(highlightColor);
}else{
Messages.setLanguageText(encryptToggle,"SpeedTestWizard.test.panel.standard");
if(originalColor!=null){
encryptToggle.setBackground(originalColor);
}
}
}//handleEvent
}
}