/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package javax.microedition.lcdui;
import java.util.Enumeration;
import java.util.Hashtable;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Control;
/**
* Implementation of LCDUI <code>Command</code> class.
*/
public class Command
{
/**
* Command type SCREEN.
*/
public static final int SCREEN = 1;
/**
* Command type BACK.
*/
public static final int BACK = 2;
/**
* Command type CANCEL.
*/
public static final int CANCEL = 3;
/**
* Command type OK.
*/
public static final int OK = 4;
/**
* Command type HELP.
*/
public static final int HELP = 5;
/**
* Command type STOP.
*/
public static final int STOP = 6;
/**
* Command type EXIT.
*/
public static final int EXIT = 7;
/**
* Command type ITEM.
*/
public static final int ITEM = 8;
private static final String EMPTY_STRING = "";
private String shortLabel;
private String longLabel;
private int type;
private int priority;
// List of eSWT's Commands associated with this Command.
// There must be one eSWT Command per Control.
private Hashtable eswtCommands = new Hashtable();
// List of priorities created. This is used when LCDUI priorities
// are mapped to eSWT priorities.
private static Hashtable priorities;
static
{
priorities = new Hashtable();
priorities.put(new Integer(Integer.MIN_VALUE),
new Integer(0));
priorities.put(new Integer(Integer.MAX_VALUE),
new Integer(Integer.MAX_VALUE));
}
/**
* Creates new Command.
*
* @param shortLabel Label of Command.
* @param type Type of command.
* @param priority Priority of command.
*/
public Command(String shortLabel, int type, int priority)
{
this(shortLabel, null, type, priority);
}
/**
* Creates new Command.
*
* @param shortLabel Label of command.
* @param longLabel Long label of command.
* @param type Type of command.
* @param priority Priority of command.
*/
public Command(String shortLabel,
String longLabel,
int type,
int priority)
{
if(shortLabel == null)
{
throw new NullPointerException(
MsgRepository.COMMAND_EXCEPTION_LABEL_IS_NULL);
}
if(type < SCREEN || type > ITEM)
{
throw new IllegalArgumentException(
MsgRepository.COMMAND_EXCEPTION_INVALID_TYPE);
}
this.type = type;
this.shortLabel = shortLabel;
this.longLabel = longLabel;
this.priority = priority;
}
/**
* Gets the label of the command.
*
* @return Label of this command.
*/
public String getLabel()
{
return shortLabel;
}
/**
* Get the long label of the command.
*
* @return Long label of this command.
*/
public String getLongLabel()
{
return longLabel;
}
/**
* Gets the command type.
*
* @return Type of this command.
*/
public int getCommandType()
{
return type;
}
/**
* Gets the priority of the command.
*
* @return Priority of this command.
*/
public int getPriority()
{
return priority;
}
/**
* Gets eSWT Command associated with this command on the queried Control.
*
* @param control the queried Control.
* @return eSWT Command.
*/
org.eclipse.ercp.swt.mobile.Command getESWTCommand(Control control)
{
if(control != null)
{
return (org.eclipse.ercp.swt.mobile.Command)
eswtCommands.get(control);
}
return null;
}
/**
* Add a SelectionListener to this command's eSWT command widget on the
* specified control.
*
* @param control
* @param listener
*/
void eswtAddCommandSelectionListener(Control control,
SelectionListener listener)
{
if(listener != null)
{
org.eclipse.ercp.swt.mobile.Command cmd = getESWTCommand(control);
if(cmd != null && !cmd.isDisposed())
{
// Remove listener if it is already added. Same listener
// should be in same command only once:
cmd.removeSelectionListener(listener);
cmd.addSelectionListener(listener);
}
}
}
/**
* Removes the SelectionListener from this command's eSWT command widget on
* the specified control.
*
* @param control
* @param listener
*/
void eswtRemoveCommandSelectionListener(Control control,
SelectionListener listener)
{
if(listener != null)
{
org.eclipse.ercp.swt.mobile.Command cmd = getESWTCommand(control);
if(cmd != null && !cmd.isDisposed())
{
cmd.removeSelectionListener(listener);
}
}
}
/**
* Adds eSWT Command to this command.
*
* @param control The Control where eSWT Command is added. For example
* Shell.
* @param isDefault If true, created eSWT command is set to be default one.
*/
void addESWTCommand(Control control, final boolean isDefault)
{
final Control finalControl = control;
ESWTUIThreadRunner.syncExec(new Runnable()
{
public void run()
{
eswtAddESWTCommand(finalControl, isDefault);
}
});
}
/**
* eSWT callback to add an eSWT Command to vector of eSWT Commands.
*
* @param control eSWT control on which the command is created.
* @param isDefault If true, created eSWT command is set to be default one.
*/
void eswtAddESWTCommand(Control control, boolean isDefault)
{
if(!eswtCommands.containsKey(control))
{
int eswtType = getEswtType(type);
int eswtPriority = getESWTPriority(priority);
org.eclipse.ercp.swt.mobile.Command eswtCommand =
new org.eclipse.ercp.swt.mobile.Command(
control, eswtType, eswtPriority);
eswtCommand.setText(shortLabel);
if(longLabel != null)
{
eswtCommand.setLongLabel(longLabel);
}
if(isDefault)
{
eswtCommand.setDefaultCommand();
}
eswtCommands.put(control, eswtCommand);
}
}
/**
* Removes eSWT Command from this command.
*
* @param control The Control where eSWT Command is located.
*/
void removeESWTCommand(Control control)
{
final Control finalControl = control;
ESWTUIThreadRunner.syncExec(new Runnable()
{
public void run()
{
eswtRemoveESWTCommand(finalControl);
}
});
}
/**
* eSWT callback to remove an eSWT Command to vector of eSWT Commands.
*/
void eswtRemoveESWTCommand(Control control)
{
if(eswtCommands.containsKey(control))
{
if(getESWTCommand(control) != null)
{
getESWTCommand(control).dispose();
}
eswtCommands.remove(control);
}
}
/**
* Get eSWT command type.
*
* @param cmdType LCDUI type
* @return mapped eSWT command type.
*/
private int getEswtType(int cmdType)
{
int eswtType = 0;
// There are no Command types SCREEN and ITEM in eSWT so
// the eSWT type GENERAL is used for those types.
switch(cmdType)
{
case SCREEN:
eswtType = org.eclipse.ercp.swt.mobile.Command.GENERAL;
break;
case BACK:
eswtType = org.eclipse.ercp.swt.mobile.Command.BACK;
break;
case CANCEL:
eswtType = org.eclipse.ercp.swt.mobile.Command.CANCEL;
break;
case OK:
eswtType = org.eclipse.ercp.swt.mobile.Command.OK;
break;
case HELP:
eswtType = org.eclipse.ercp.swt.mobile.Command.HELP;
break;
case STOP:
eswtType = org.eclipse.ercp.swt.mobile.Command.STOP;
break;
case EXIT:
eswtType = org.eclipse.ercp.swt.mobile.Command.EXIT;
break;
case ITEM:
eswtType = org.eclipse.ercp.swt.mobile.Command.GENERAL;
break;
default:
break;
}
return eswtType;
}
/**
* If Command is created with empty label ("") then system should use
* default label depending of Command type. This method will return the
* default label. Method assumes that the type-field is initialized before
* this method is called.
*
* @return Default label.
*/
static String getDefaultLabel(int type)
{
String rValue;
switch(type)
{
case SCREEN:
rValue = MsgRepository.COMMAND_LABEL_SCREEN;
break;
case BACK:
rValue = MsgRepository.COMMAND_LABEL_BACK;
break;
case CANCEL:
rValue = MsgRepository.COMMAND_LABEL_CANCEL;
break;
case OK:
rValue = MsgRepository.COMMAND_LABEL_OK;
break;
case HELP:
rValue = MsgRepository.COMMAND_LABEL_HELP;
break;
case STOP:
rValue = MsgRepository.COMMAND_LABEL_STOP;
break;
case EXIT:
rValue = MsgRepository.COMMAND_LABEL_EXIT;
break;
case ITEM:
rValue = MsgRepository.COMMAND_LABEL_ITEM;
break;
default:
rValue = EMPTY_STRING;
break;
}
return rValue;
}
/**
* In eSWT lowest possible priority value is 0, but in LCDUI it's ok to have
* negative priority values. This method converts LCDUI priority to eSWT
* priority. In practise the method provides acceptable priorities for all
* kind of applications, but in theory, in worst case scenario, if using
* very uncommon priority numbering scheme and if there are more than 31
* commands and every command has different priority than other commands,
* then same priority might be returned more than once.
*
* The meaning of variables:
* <li>a = nearest smaller lcdui priority.
* <li>b = nearest larger lcdui priority.
* <li>c = lcdui priority to be converted.
* <li>a1 = eswt priority value associated with a.
* <li>b1 = eswt priority value associated with b.
* <li>c1 = eswt priority value associated with c.
* <li>x = value in the middle of a1 and b1.
* <li>ac = distance from a to c.
* <li>cb = distance from c to b.
* <li>a1x = distance from a1 to x.
*
* @param c Lcdui priority to be converted.
* @see OpenLCDUI design document for more detailed description of the
* algorithm.
*/
private int getESWTPriority(int c)
{
// Find out nearest values from keys (LCDUI priorities). "a" will
// be nearest smaller value and "b" will be nearest larger value.
Integer a = new Integer(Integer.MIN_VALUE);
Integer b = new Integer(Integer.MAX_VALUE);
for(Enumeration e = priorities.keys(); e.hasMoreElements();)
{
Integer i = (Integer) e.nextElement();
if((i.intValue() >= a.intValue()) && (i.intValue() <= c))
{
a = i;
}
if((i.intValue() <= b.intValue()) && (i.intValue() >= c))
{
b = i;
}
}
// Calculate eSWT priority candidate. "a1" is nearest
// smaller value in eSWT priorities and "b1" is nearest
// larger value and x is the candidate:
int a1 = ((Integer) priorities.get(a)).intValue();
int b1 = ((Integer) priorities.get(b)).intValue();
int a1x = ((b1 - a1) / 2);
int x = a1x + a1;
// Calculate distances from new LCDUI priority to nearest
// LCDUI priorities already saved:
long ac = Math.abs((long) a.intValue() - (long) c);
long cb = Math.abs((long) b.intValue() - (long) c);
// Decide whether to use candidate or one of the nearest values:
int c1 = 0;
if(ac > cb)
{
if(cb < a1x)
{
// Use nearest larger value:
c1 = (int)(b1 - cb);
}
else
{
// Use candidate:
c1 = x;
}
}
else
{
if(ac < a1x)
{
// Use nearest smaller value:
c1 = (int)(a1 + ac);
}
else
{
// Use candidate:
c1 = x;
}
}
// Save new priority to the HashTable if not already exists.
if(!priorities.contains(new Integer(c1)))
{
priorities.put(new Integer(c), new Integer(c1));
}
// Return flipped priority because in LCDUI lower priority
// means higher importance, but in eSWT lower priority means
// lower importance:
return Integer.MAX_VALUE - c1;
}
}