package jadex.tools.simcenter;
import jadex.base.service.simulation.ISimulationService;
import jadex.commons.concurrent.SwingDefaultResultListener;
import jadex.commons.service.SServiceProvider;
import jadex.commons.service.clock.IClock;
import jadex.commons.service.clock.IClockService;
import jadex.commons.service.threadpool.IThreadPoolService;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.DecimalFormat;
import java.text.ParseException;
import javax.swing.AbstractSpinnerModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;
/**
* The clock panel shows the settings for a clock object.
*/
public class ClockPanel extends AbstractTimePanel
{
//-------- attributes --------
/** The sim center panel. */
protected SimCenterPanel simp;
/** The simulation mode. */
protected JComboBox emode;
/** The clock name. */
//protected JLabel name;
/** The start time. */
protected JTextField starttime;
/** The tick size. */
protected JTextField ticksize;
protected JTextField curticksize;
/** The dilation. */
protected JSpinner dilation;
protected JTextField curdilation;
/** The current time. */
protected JLabel currenttime;
/** The relative time flag. */
//protected JCheckBox relative;
/** The tick count. */
protected JLabel tickcount;
/** The current system time. */
protected JLabel systemtime;
/** The last clocktype (used to check if update of gui items is necessary). */
protected String lastclocktype;
/** Format. */
protected DecimalFormat numberformat;
//-------- constructors --------
/**
* Create a clock panel.
* @param clock The clock.
*/
public ClockPanel(final SimCenterPanel simp)
{
super(simp.getServiceContainer());
this.setLayout(new GridBagLayout());
//this.clock = clock;
//this.context = context;
this.simp = simp;
this.numberformat = new DecimalFormat("#######0.####");
this.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), "Clock Settings "));
int x=0;
int y=0;
final JCheckBox update = new JCheckBox("Update clock", true);
update.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setActive(update.isSelected());
}
});
this.add(update, new GridBagConstraints(x,y,2,1,0,0,
GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
emode = new JComboBox(new String[]{"System", "Continuous", "Time Stepped", "Event Driven"});
emode.setEditable(false);
this.add(new JLabel("Execution mode"), new GridBagConstraints(x,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(emode, new GridBagConstraints(++x,y,2,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
/*this.name = new JLabel();
this.add(new JLabel("Clock name"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(name, new GridBagConstraints(++x,y,1,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));*/
starttime = new JTextField(8);
starttime.setEditable(false);
this.add(new JLabel("Start time"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(starttime, new GridBagConstraints(++x,y,2,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
ticksize = new JTextField(8);
curticksize = new JTextField(4);
curticksize.setEditable(false);
this.add(new JLabel("Tick size"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(curticksize, new GridBagConstraints(++x,y,1,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
this.add(ticksize, new GridBagConstraints(++x,y,1,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
// Only for realtime
dilation = new JSpinner(new ExponentialSpinnerModel(1, 2))
{
// Override to avoid button writing textfield value into model
public void commitEdit() throws ParseException
{
}
};
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor)dilation.getEditor();
JFormattedTextField tf = editor.getTextField();
//DecimalFormat df = new DecimalFormat("######0.#####");
tf.setFormatterFactory(new DefaultFormatterFactory(new NumberFormatter(numberformat)));
tf.setEditable(true);
//if(context.getClock() instanceof IContinuousClock)
// dilation.setText(""+((IContinuousClock)context.getClock()).getDilation());
curdilation = new JTextField(3);
curdilation.setEditable(false);
this.add(new JLabel("Dilation"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(curdilation, new GridBagConstraints(++x,y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
this.add(dilation, new GridBagConstraints(++x,y,1,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
currenttime = new JLabel();
/*relative = new JCheckBox("Relative", true);
JPanel tp = new JPanel(new BorderLayout());
tp.add(currenttime, "Center");
tp.add(relative, "East");*/
this.add(new JLabel("Model time"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(currenttime, new GridBagConstraints(++x,y,2,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
tickcount = new JLabel();
this.add(new JLabel("Tick count"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(tickcount, new GridBagConstraints(++x,y,2,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
systemtime = new JLabel();
this.add(new JLabel("System time"), new GridBagConstraints(x=0,++y,1,1,0,0,
GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
this.add(systemtime, new GridBagConstraints(++x,y,2,1,1,0,
GridBagConstraints.EAST,GridBagConstraints.HORIZONTAL,new Insets(4,2,2,4),0,0));
JButton refresh = new JButton("Refresh");
JButton apply = new JButton("Apply");
JPanel buts = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buts.add(refresh);
buts.add(apply);
//this.add(buts, new GridBagConstraints(x=0,++y,2,1,1,0,
// GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(4,2,2,4),0,0));
// final IThreadPool tp = (IThreadPool)getPlatform().getService(ThreadPoolService.class);
emode.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
if("System".equals(emode.getSelectedItem()))
{
SServiceProvider.getService(getServiceProvider(),
IThreadPoolService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
final IThreadPoolService tp = (IThreadPoolService)result;
SServiceProvider.getService(getServiceProvider(),
ISimulationService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
ISimulationService sims = (ISimulationService)result;
if(!IClock.TYPE_SYSTEM.equals(lastclocktype))
{
sims.setClockType(IClock.TYPE_SYSTEM, tp);
// updateView();
simp.updateView();
}
}
});
}
});
}
else if("Continuous".equals(emode.getSelectedItem()))
{
SServiceProvider.getService(getServiceProvider(),
IThreadPoolService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
final IThreadPoolService tp = (IThreadPoolService)result;
SServiceProvider.getService(getServiceProvider(),
ISimulationService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
ISimulationService sims = (ISimulationService)result;
if(!IClock.TYPE_CONTINUOUS.equals(lastclocktype))
{
sims.setClockType(IClock.TYPE_CONTINUOUS, tp);
// updateView();
simp.updateView();
}
}
});
}
});
}
else if("Time Stepped".equals(emode.getSelectedItem()))
{
SServiceProvider.getService(getServiceProvider(),
IThreadPoolService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
final IThreadPoolService tp = (IThreadPoolService)result;
SServiceProvider.getService(getServiceProvider(),
ISimulationService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
ISimulationService sims = (ISimulationService)result;
if(!IClock.TYPE_TIME_DRIVEN.equals(lastclocktype))
{
sims.setClockType(IClock.TYPE_TIME_DRIVEN, tp);
// updateView();
simp.updateView();
}
}
});
}
});
}
else if("Event Driven".equals(emode.getSelectedItem()))
{
SServiceProvider.getService(getServiceProvider(),
IThreadPoolService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
final IThreadPoolService tp = (IThreadPoolService)result;
SServiceProvider.getService(getServiceProvider(),
ISimulationService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
ISimulationService sims = (ISimulationService)result;
if(!IClock.TYPE_EVENT_DRIVEN.equals(lastclocktype))
{
sims.setClockType(IClock.TYPE_EVENT_DRIVEN, tp);
// updateView();
simp.updateView();
}
}
});
}
});
}
else
{
throw new RuntimeException("Unsupported clock type: "+emode.getSelectedItem());
}
}
});
dilation.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
SServiceProvider.getService(getServiceProvider(),
IClockService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
IClockService cs = (IClockService)result;
if(!IClock.TYPE_CONTINUOUS.equals(cs.getClockType()))
return;
try
{
double dil = ((Double)dilation.getValue()).doubleValue();
cs.setDilation(dil);
}
catch(NumberFormatException ex)
{
}
}
});
}
});
ticksize.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
SServiceProvider.getService(getServiceProvider(),
IClockService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
IClockService cs = (IClockService)result;
try
{
long tick = Long.parseLong(ticksize.getText());
cs.setDelta(tick);
//System.out.println("Setting tick size to: "+tick);
}
catch(NumberFormatException ex)
{
ex.printStackTrace();
}
}
});
}
});
refresh.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
updateView();
}
});
/*relative.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(relative.isSelected())
currenttime.setText(""+timeformat.format(getContext().getClock().getTime()));
else
currenttime.setText(""+dateformat.format(new Date(getContext().getClock().getTime())));
}
});*/
setActive(true);
}
// long time;
// int cnt;
/**
* Update the view.
*/
public synchronized void updateView()
{
// cnt++;
// if(System.currentTimeMillis()-time>1000)
// {
// System.out.println("ClockPanel.updateView called "+cnt+" times.");
// cnt = 0;
// time = System.currentTimeMillis();
// }
SServiceProvider.getService(getServiceProvider(),
IClockService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
final IClockService cs = (IClockService)result;
SServiceProvider.getService(getServiceProvider(),
ISimulationService.class).addResultListener(new SwingDefaultResultListener(ClockPanel.this)
{
public void customResultAvailable(Object source, Object result)
{
ISimulationService sims = (ISimulationService)result;
String tsstring = curticksize.getText();
String tsstring_new = ""+numberformat.format(cs.getDelta());
if(!tsstring.equals(tsstring_new))
curticksize.setText(tsstring_new);
String ststring = starttime.getText();
String ststring_new = ""+cs.getStarttime();
if(!ststring.equals(ststring_new))
starttime.setText(ststring_new);
//name.setText(""+getContext().getClock());
/*if(relative.isSelected())
currenttime.setText(""+timeformat.format(getContext().getClock().getTime()));
else
currenttime.setText(""+dateformat.format(new Date(getContext().getClock().getTime())));
*/
currenttime.setText(simp.formatTime(cs.getTime()));
tickcount.setText(""+cs.getTick());
systemtime.setText(simp.formatTime(System.currentTimeMillis()));
if(cs.getClockType().equals(IClock.TYPE_CONTINUOUS))
{
String dstring = curdilation.getText();
String dstring_new = ""+cs.getDilation();
if(!dstring.equals(dstring_new))
{
curdilation.setText(dstring_new);
}
}
// Clock change actions
if(lastclocktype==null || !lastclocktype.equals(cs.getClockType()))
{
lastclocktype = cs.getClockType();
curticksize.setText(""+cs.getDelta());
ticksize.setText(""+cs.getDelta());
if(lastclocktype.equals(IClock.TYPE_SYSTEM))
{
emode.setSelectedItem("System");
dilation.setValue(new Double(0));
curdilation.setText("");
}
else if(lastclocktype.equals(IClock.TYPE_CONTINUOUS))
{
emode.setSelectedItem("Continuous");
dilation.setValue(new Double(cs.getDilation()));
curdilation.setText(""+cs.getDilation());
}
else if(lastclocktype.equals(IClock.TYPE_TIME_DRIVEN))
{
emode.setSelectedItem("Time Stepped");
dilation.setValue(new Double(0));
curdilation.setText("");
}
else if(lastclocktype.equals(IClock.TYPE_EVENT_DRIVEN))
{
emode.setSelectedItem("Event Driven");
dilation.setValue(new Double(0));
curdilation.setText("");
}
}
if(lastclocktype.equals(IClock.TYPE_CONTINUOUS))// && !getContext().isRunning())
{
if(!dilation.isEnabled())
{
dilation.setEnabled(true);
((JSpinner.DefaultEditor)dilation.getEditor()).getTextField().setEditable(true);
}
}
else
{
if(dilation.isEnabled())
{
dilation.setEnabled(false);
((JSpinner.DefaultEditor)dilation.getEditor()).getTextField().setEditable(false);
}
}
emode.setEnabled(!sims.isExecuting());
}
});
}
});
}
}
/**
* The exponential spinner model.
*/
class ExponentialSpinnerModel extends AbstractSpinnerModel
{
//-------- attributes --------
/** The current value. */
protected double value;
/** The growth rate. */
protected double rate;
//-------- constructors --------
/**
* Create a new model.
*/
public ExponentialSpinnerModel(double value, double rate)
{
this.value = value;
this.rate = rate;
}
//-------- methods --------
/**
* Get the next value.
* @return The next value.
*/
public Object getNextValue()
{
//System.out.println("nv: "+value*rate);
return new Double(value*rate);
}
/**
* Get the previous value.
* @return The previous value.
*/
public Object getPreviousValue()
{
//System.out.println("pv: "+value/rate);
return new Double(value/rate);
}
/**
* Get the current value.
* @return The current value.
*/
public Object getValue()
{
//System.out.println("gV: "+value);
return new Double(value);
}
/**
* Set the current value.
* @param value The current value.
*/
public void setValue(Object value)
{
//System.out.println("YYY: "+value);
//Thread.dumpStack();
if((value == null) || !(value instanceof Number))
throw new IllegalArgumentException("Illegal value: "+value);
if(!value.equals(new Double(this.value)))
{
this.value = ((Number)value).doubleValue();
fireStateChanged();
}
}
}