Tables now available

git-svn-id: http://svn.3splooges.com/romraider-arch/trunk@578 d2e2e1cd-ba16-0410-be16-b7c4453c7c2d
This commit is contained in:
Tgui 2007-03-19 20:33:18 +00:00
parent 873a3910b0
commit 747a6c06f9
13 changed files with 507 additions and 59 deletions

View File

@ -25,7 +25,9 @@ import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeSelectionModel;
import enginuity.NewGUI.data.DataManager;
import enginuity.NewGUI.data.ApplicationStateManager;
import enginuity.NewGUI.data.TableNodeMetaData;
import enginuity.NewGUI.etable.EJTable;
import enginuity.NewGUI.interfaces.TuningEntity;
import enginuity.NewGUI.interfaces.TuningEntityListener;
import enginuity.NewGUI.tree.ETree;
@ -46,7 +48,7 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
private JSplitPane splitPane = new JSplitPane();
private JDesktopPane rightDesktopPane = new JDesktopPane();
private ETreeNode rootNode = new ETreeNode(ETreeNode.RESERVED_ROOT, "Enginuity");
private ETreeNode rootNode = new ETreeNode(ETreeNode.RESERVED_ROOT, "Enginuity", null);
private ETree leftJTree = new ETree(rootNode);
private NewGUI(){
@ -58,18 +60,18 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
}
public static NewGUI getInstance(){
if(instance == null){
instance = new NewGUI();
if(ApplicationStateManager.getEnginuityInstance() == null){
ApplicationStateManager.setEnginuityInstance(new NewGUI());
}
return instance;
return ApplicationStateManager.getEnginuityInstance();
}
private void initData(){
// Add supported tuning entities
UtecTuningEntityImpl utei = new UtecTuningEntityImpl();
DataManager.addTuningEntity(utei);
ApplicationStateManager.addTuningEntity(utei);
}
private void initGui(){
@ -85,7 +87,7 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
// Setup JMenu
Iterator tuningEntities = DataManager.getTuningEntities().iterator();
Iterator tuningEntities = ApplicationStateManager.getTuningEntities().iterator();
while(tuningEntities.hasNext()){
TuningEntity theTuningEntity = (TuningEntity)tuningEntities.next();
JMenuItem tempItem = new JMenuItem(theTuningEntity.getName());
@ -95,16 +97,8 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
this.jMenuBar.add(this.tuningEntitiesJMenu);
this.setJMenuBar(this.jMenuBar);
// Test internalFrames
JInternalFrame internalTest = new JInternalFrame("Test Internal", true, true, true, true);
internalTest.setSize(300,300);
internalTest.setVisible(true);
// Setup desktop pane
rightDesktopPane.setBackground(Color.BLACK);
rightDesktopPane.add(internalTest);
// Setup split pane
@ -127,7 +121,7 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
String theCommand = e.getActionCommand();
DataManager.setCurrentTuningEntity(theCommand, this);
ApplicationStateManager.setCurrentTuningEntity(theCommand, this);
}
}
@ -136,8 +130,6 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
this.rootNode.add(treeRootNode);
this.leftJTree.updateUI();
this.splitPane.repaint();
System.out.println("Changed the tree model");
}
@ -163,5 +155,14 @@ public class NewGUI extends JFrame implements ActionListener, TreeSelectionListe
this.rebuildJTree(newTreeModel);
}
public void displayInternalFrameTable(double[][] data, TableNodeMetaData tableMetaData){
// Add internal frame
JInternalFrame newInternalFrame = new JInternalFrame(tableMetaData.getTableName(), true, true, true, true);
EJTable newTable = new EJTable(tableMetaData, data);
newInternalFrame.add(newTable);
newInternalFrame.setVisible(true);
newInternalFrame.setSize(300,300);
this.rightDesktopPane.add(newInternalFrame);
}
}

View File

@ -3,12 +3,23 @@ package enginuity.NewGUI.data;
import java.util.Iterator;
import java.util.Vector;
import enginuity.NewGUI.NewGUI;
import enginuity.NewGUI.interfaces.TuningEntity;
import enginuity.NewGUI.interfaces.TuningEntityListener;
public class DataManager {
public class ApplicationStateManager {
public static final int USER_LEVEL_1 = 1;
public static final int USER_LEVEL_2 = 2;
public static final int USER_LEVEL_3 = 3;
public static final int USER_LEVEL_4 = 4;
public static final int USER_LEVEL_5 = 5;
private static Vector<TuningEntity> tuningEntities = new Vector<TuningEntity>();
private static TuningEntity currentTuningEntity;
private static int currentUserLevel = ApplicationStateManager.USER_LEVEL_1;
private static NewGUI enginuityInstance = null;
public static Vector<TuningEntity> getTuningEntities() {
return tuningEntities;
@ -34,4 +45,24 @@ public class DataManager {
}
}
}
public static int getCurrentUserLevel() {
return currentUserLevel;
}
public static void setCurrentUserLevel(int currentUserLevel) {
ApplicationStateManager.currentUserLevel = currentUserLevel;
}
public static TuningEntity getCurrentTuningEntity() {
return currentTuningEntity;
}
public static NewGUI getEnginuityInstance() {
return enginuityInstance;
}
public static void setEnginuityInstance(NewGUI enginuityInstance) {
ApplicationStateManager.enginuityInstance = enginuityInstance;
}
}

View File

@ -0,0 +1,39 @@
package enginuity.NewGUI.data;
public class TableNodeMetaData {
private double maxValue;
private double minValue;
private Object[] ignoredValues;
private boolean isInvertedColoring;
private String tableName;
public TableNodeMetaData(double minValue, double maxValue, Object[] ignoredValues, boolean isInvertedColoring, String tableName) {
this.maxValue = maxValue;
this.minValue = minValue;
this.ignoredValues = ignoredValues;
this.isInvertedColoring = isInvertedColoring;
this.tableName = tableName;
System.out.println("Min:"+this.minValue+ " Max:"+this.maxValue + " Name:"+this.tableName+ " Inv:"+this.isInvertedColoring);
}
public Object[] getIgnoredValues() {
return ignoredValues;
}
public boolean isInvertedColoring() {
return isInvertedColoring;
}
public double getMaxValue() {
return maxValue;
}
public double getMinValue() {
return minValue;
}
public String getTableName() {
return tableName;
}
}

View File

@ -0,0 +1,126 @@
package enginuity.NewGUI.etable;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import enginuity.NewGUI.data.TableNodeMetaData;
public class EJTable extends JTable{
private ETableModel theModel;
public EJTable(TableNodeMetaData metaData, double[][] data){
this.theModel = new ETableModel(metaData.getTableName(), data);
//TODO update, possible issue here
super.setModel(this.theModel);
//this.setSelectionModel(ListSelectionModel.)
this.setCellSelectionEnabled(true);
this.getSelectionModel().addListSelectionListener(new ESelectionListener(this));
this.setDefaultRenderer(Object.class, new ETableCellRenderer(metaData.getMinValue(), metaData.getMaxValue(), metaData.getIgnoredValues(), metaData.isInvertedColoring()));
//this.setSelectedQuadrilateral(2,4,4,7);
//this.incSelectedCells(22);
// this.setSelected(0,0);
// this.setSelected(1,1);
// this.incSelectedCells(22);
//this.setSelected(3,5);
}
/**
* Zero based row and columns, inclusive
*
* @param rowStart
* @param rowEnd
* @param colStart
* @param colEnd
*/
public void setSelectedQuadrilateral(int rowStart, int rowEnd, int colStart, int colEnd){
for(int i = rowStart; i < rowEnd + 1; i++){
for(int j = colStart; j < colEnd + 1; j++){
this.changeSelection(i, j, false, true);
}
}
}
/**
* Set a cell as being selected.
*
* @param rowIndex
* @param colIndex
*/
public void setSelected(int rowIndex, int colIndex){
this.changeSelection(rowIndex, colIndex, false, true);
}
/**
* Increment cell values by passed double amount.
* @param amount
*/
public void incSelectedCells(double amount){
int rowStart = this.getSelectedRow();
int rowEnd = this.getSelectionModel().getMaxSelectionIndex();
int colStart = this.getSelectedColumn();
int colEnd = this.getColumnModel().getSelectionModel().getMaxSelectionIndex();
for(int i = rowStart; i <= rowEnd; i++){
for(int j = colStart; j <= colEnd; j++){
if(this.isCellSelected(i,j)){
// The cell is selected
Object value = theModel.getValueAt(i, j);
System.out.println("Selection found at:"+i+" :"+j);
if(value instanceof Double){
Double temp = (Double)value + amount;
//theModel.setValueAt(temp, i, j);
theModel.setDoubleData(i,j,temp);
}
}
}
}
}
/**
* Decrement cell values by passed double amount.
* @param amount
*/
public void decSelectedCells(double amount){
int rowStart = this.getSelectedRow();
int rowEnd = this.getSelectionModel().getMaxSelectionIndex();
int colStart = this.getSelectedColumn();
int colEnd = this.getColumnModel().getSelectionModel().getMaxSelectionIndex();
for(int i = rowStart; i <= rowEnd; i++){
for(int j = colStart; j <= colEnd; j++){
if(this.isCellSelected(i,j)){
// The cell is selected
Object value = theModel.getValueAt(i, j);
if(value instanceof Double){
Double temp = (Double)value - amount;
//theModel.setValueAt(temp, i, j);
theModel.setDoubleData(i,j,temp);
}
}
}
}
}
/**
* Replace all table data with passed data.
* @param newData
*/
public void replaceAlltableData(double[][] newData){
((ETableModel)this.dataModel).replaceData(newData);
}
}

View File

@ -0,0 +1,34 @@
package enginuity.NewGUI.etable;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class ESelectionListener implements ListSelectionListener{
private JTable parentTable = null;
public ESelectionListener(JTable parentTable){
this.parentTable = parentTable;
}
public void valueChanged(ListSelectionEvent event) {
//System.out.println("1: "+ event.getFirstIndex()+" 2: "+event.getLastIndex());
int selRow[] = parentTable.getSelectedRows();
int selCol[] = parentTable.getSelectedColumns();
for(int i = 0; i < selRow.length; i++){
//System.out.println("Row Value: "+selRow[i]);
}
for(int i = 0; i < selCol.length; i++){
//System.out.println("Col Value: "+selCol[i]);
}
//System.out.println("---------------------------");
Object[] selectedCells = new Object[selRow.length * selCol.length];
}
}

View File

@ -0,0 +1,71 @@
package enginuity.NewGUI.etable;
import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.vecmath.Color3f;
import com.ecm.graphics.tools.ColorTable;
public class ETableCellRenderer extends DefaultTableCellRenderer{
private double min;
private double max;
private Object[] ignoredValues;
private boolean isInvertedColoring;
public ETableCellRenderer(double min, double max, Object[] ignoredValues, boolean isInvertedColoring){
this.min = min;
this.max = max;
this.ignoredValues = ignoredValues;
this.isInvertedColoring = isInvertedColoring;
}
/**
* Called when table needs cell rendering information. Cell logic on color values goes here.
*/
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col){
Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if(isSelected){
cell.setBackground(Color.BLUE);
}else{
if(value instanceof Double){
ColorTable.initColorTable(min, max);
if(this.isInvertedColoring){
ColorTable.initColorTable(max, min);
}
Color3f theColor = ColorTable.getColor((Double)value);
cell.setBackground(new Color(theColor.x, theColor.y, theColor.z));
// If out of range color cell red
if((Double)value < min || (Double)value > max){
cell.setBackground(Color.RED);
}
}
// Iterate through the ignored values, paint them gray
for(int i = 0; i < ignoredValues.length; i++){
// Double ignored values
if((value instanceof Double) && (ignoredValues[i] instanceof Double)){
Double doubleValue = (Double)value;
Double ignoredValue = (Double)ignoredValues[i];
if((doubleValue - ignoredValue) == 0){
cell.setBackground(Color.GRAY);
}
}
// Maybe add string value detection as needed
}
}
return cell;
}
}

View File

@ -0,0 +1,90 @@
package enginuity.NewGUI.etable;
import javax.swing.table.AbstractTableModel;
public class ETableModel extends AbstractTableModel {
private String[] columnNames = new String[11];
private double[][] data = new double[11][40];
String test = "";
private String tableName;
public ETableModel(String tableName, double[][] initialData) {
this.tableName = tableName;
this.data = initialData;
for (int i = 0; i < columnNames.length; i++) {
columnNames[i] = i + "";
}
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return 40;
}
public Object getValueAt(int row, int col) {
return data[col][row];
}
public String getColumnName(int col) {
return columnNames[col];
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
//System.out.print(" Updated:"+(String)value+": ");
// Set new data in table
double temp = data[col][row];
if(value instanceof String){
try{
temp = Double.parseDouble((String)value);
}catch (NumberFormatException e) {
System.out.println("Not a valid number entered.");
}
data[col][row] = temp;
}else if(value instanceof Double){
data[col][row] = (Double)value;
}
// TODO RE IMPLEMENT
// Update current map in scope
/*
if(this.identifier == MapJPanel.FUELMAP){
UtecDataManager.setFuelMapValue(row, col, temp);
}
else if(this.identifier == MapJPanel.TIMINGMAP){
UtecDataManager.setTimingMapValue(row, col, temp);
}
else if(this.identifier == MapJPanel.BOOSTMAP){
UtecDataManager.setBoostMapValue(row, col, temp);
}
*/
this.fireTableDataChanged();
}
public void setDoubleData(int row, int col, double value){
this.data[col][row] = value;
}
public void replaceData(double[][] newData){
System.out.println("Model data being replaced in full.");
this.data = newData;
this.fireTableDataChanged();
}
}

View File

@ -0,0 +1,13 @@
package enginuity.NewGUI.etable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
public class ETableSelectionListener implements TableModelListener{
public void tableChanged(TableModelEvent arg0) {
// TODO Auto-generated method stub
}
}

View File

@ -18,6 +18,9 @@ public interface TuningEntity extends ActionListener{
// Return double data based on passed table name
public double[][] getTableData(String tableName);
// Push back modified data to the tuning entity
public double[][] setTableData(String tableName, double[][] data);
// Control methods
public void init(TuningEntityListener listener);
}

View File

@ -6,6 +6,7 @@ import java.awt.event.MouseListener;
import javax.swing.JTree;
import enginuity.NewGUI.data.ApplicationStateManager;
import enginuity.swing.RomCellRenderer;
public class ETree extends JTree implements MouseListener {
@ -19,9 +20,32 @@ public class ETree extends JTree implements MouseListener {
setFont(new Font("Tahoma", Font.PLAIN, 11));
}
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
public void mouseClicked(MouseEvent e) {
if(e == null){
return;
}
if(getPathForLocation(e.getX(), e.getY()) == null){
return;
}
Object selectedObject = getPathForLocation(e.getX(), e.getY()).getLastPathComponent();
// Null selection occurs when no tree row is selected
if(selectedObject == null){
return;
}
if(selectedObject instanceof ETreeNode){
ETreeNode theNode = (ETreeNode)selectedObject;
// If this is a table that contains data, then open it in the right pane in an internal frame
if(theNode.getNodeType() == ETreeNode.DATA1D || theNode.getNodeType() == ETreeNode.DATA2D || theNode.getNodeType() == ETreeNode.DATA3D){
System.out.println("Table data");
double[][] tableData = ApplicationStateManager.getCurrentTuningEntity().getTableData(theNode.getNodeName());
ApplicationStateManager.getEnginuityInstance().displayInternalFrameTable(tableData, theNode.getTableMetaData());
}
}
}
public void mousePressed(MouseEvent arg0) {

View File

@ -15,14 +15,12 @@ import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import enginuity.NewGUI.data.ApplicationStateManager;
public class ETreeCellRenderer implements TreeCellRenderer{
DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
public ETreeCellRenderer(){
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
@ -72,7 +70,6 @@ public class ETreeCellRenderer implements TreeCellRenderer{
}else if(eTreeNode.getNodeType() == ETreeNode.DATA3D || eTreeNode.getNodeType() == ETreeNode.DATA2D || eTreeNode.getNodeType() == ETreeNode.DATA1D){
// set color
namedJPanel.add(nodeName);
nodeName.setFont(new Font("Tahoma", Font.PLAIN, 11));
@ -81,21 +78,16 @@ public class ETreeCellRenderer implements TreeCellRenderer{
namedJPanel.setBorder(createLineBorder(new Color(0, 0, 225)));
}
// TODO Imlement user level
if (eTreeNode.getUserLevel() == 5) {
nodeName.setForeground(new Color(255, 150, 150));
nodeName.setFont(new Font("Tahoma", Font.ITALIC, 11));
}
/*else if (eTreeNode.getUserLevel() > table.getRom().getContainer().getSettings().getUserLevel()) {
else if (eTreeNode.getUserLevel() > ApplicationStateManager.getCurrentUserLevel()) {
//tableName.setForeground(new Color(185, 185, 185));
tableName.setFont(new Font("Tahoma", Font.ITALIC, 11));
nodeName.setFont(new Font("Tahoma", Font.ITALIC, 11));
}
*/
returnValue = namedJPanel;
}

View File

@ -1,8 +1,8 @@
package enginuity.NewGUI.tree;
import java.util.LinkedList;
import javax.swing.tree.DefaultMutableTreeNode;
import enginuity.NewGUI.data.ApplicationStateManager;
import enginuity.NewGUI.data.TableNodeMetaData;
public class ETreeNode extends DefaultMutableTreeNode{
public static final int DATA1D = 0;
@ -10,22 +10,19 @@ public class ETreeNode extends DefaultMutableTreeNode{
public static final int DATA3D = 3;
public static final int CATEGORY = 4;
public static final int RESERVED_ROOT = 5;
public static final int USER_LEVEL_1 = 6;
public static final int USER_LEVEL_2 = 7;
public static final int USER_LEVEL_3 = 8;
public static final int USER_LEVEL_4 = 9;
public static final int USER_LEVEL_5 = 10;
private int userLevel = ETreeNode.USER_LEVEL_1;
private int userLevel = ApplicationStateManager.USER_LEVEL_1;
private int nodeType;
private String nodeName = "";
private TableNodeMetaData tableMetaData = null;
public ETreeNode(int nodeType, String nodeName){
public ETreeNode(int nodeType, String nodeName, TableNodeMetaData tableMetaData){
super(nodeName);
this.nodeType = nodeType;
this.nodeName = nodeName;
this.tableMetaData = tableMetaData;
}
@ -47,4 +44,9 @@ public class ETreeNode extends DefaultMutableTreeNode{
public void setUserLevel(int userLevel) {
this.userLevel = userLevel;
}
public TableNodeMetaData getTableMetaData() {
return tableMetaData;
}
}

View File

@ -16,12 +16,14 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import enginuity.NewGUI.data.TableNodeMetaData;
import enginuity.NewGUI.interfaces.TuningEntity;
import enginuity.NewGUI.interfaces.TuningEntityListener;
import enginuity.NewGUI.tree.ETreeNode;
import enginuity.logger.utec.commInterface.UtecInterface;
import enginuity.logger.utec.gui.mapTabs.UtecDataManager;
import enginuity.logger.utec.mapData.UtecMapData;
import enginuity.logger.utec.properties.UtecProperties;
public class UtecTuningEntityImpl implements TuningEntity{
@ -144,21 +146,29 @@ public class UtecTuningEntityImpl implements TuningEntity{
}
public double[][] getTableData(String tableName) {
// TODO Auto-generated method stub
return null;
double[][] data;
if(UtecDataManager.getCurrentMapData() == null){
return new double[0][0];
}
if(tableName == "Fuel"){
data = UtecDataManager.getCurrentMapData().getFuelMap();
}else if(tableName == "Timing"){
data = UtecDataManager.getCurrentMapData().getTimingMap();
}else if(tableName == "Boost"){
data = UtecDataManager.getCurrentMapData().getBoostMap();
}else{
data = new double[0][0];
}
return data;
}
public void init(TuningEntityListener theTEL) {
this.theTEL = theTEL;
// Initialise tree
ETreeNode root = new ETreeNode(ETreeNode.CATEGORY, "No map selected....");
ETreeNode fuel = new ETreeNode(ETreeNode.DATA3D, "Fuel");
ETreeNode timing = new ETreeNode(ETreeNode.DATA3D, "Timing");
ETreeNode boost = new ETreeNode(ETreeNode.DATA3D, "Boost");
root.add(fuel);
root.add(timing);
root.add(boost);
ETreeNode root = new ETreeNode(ETreeNode.CATEGORY, "UTEC: No map selected....", null);
// Inform main GUI of initial tree
@ -270,15 +280,22 @@ public class UtecTuningEntityImpl implements TuningEntity{
UtecDataManager.setCurrentMap(mapData);
}
// Initialise tree
ETreeNode root = new ETreeNode(ETreeNode.CATEGORY, "UTEC:"+UtecDataManager.getCurrentMapData().getMapName()+", "+UtecDataManager.getCurrentMapData().getMapComment(), null);
Object[] ignored = {new Double(-100.0)};
ETreeNode fuel = new ETreeNode(ETreeNode.DATA3D, "Fuel", new TableNodeMetaData(Double.parseDouble(UtecProperties.getProperties("utec.fuelMapMin")[0]), Double.parseDouble(UtecProperties.getProperties("utec.fuelMapMax")[0]), ignored, false, "Fuel" ));
// Call GUI with new map data tree
Hashtable newTable = new Hashtable();
newTable.put("UTEC", new ETreeNode(ETreeNode.CATEGORY, UtecDataManager.getCurrentMapData().getMapName()));
newTable.put("FUEL", new ETreeNode(ETreeNode.DATA3D, "fuel"));
newTable.put("TIMING", new ETreeNode(ETreeNode.DATA3D, "timing"));
newTable.put("BOOST", new ETreeNode(ETreeNode.DATA3D, "boost"));
Object[] ignored2 = {new Double(-100.0)};
ETreeNode timing = new ETreeNode(ETreeNode.DATA3D, "Timing", new TableNodeMetaData(Double.parseDouble(UtecProperties.getProperties("utec.timingMapMin")[0]), Double.parseDouble(UtecProperties.getProperties("utec.timingMapMax")[0]), ignored, false, "Timing" ));
this.theTEL.TreeStructureChanged(null);
Object[] ignored3 = {new Double(-100.0)};
ETreeNode boost = new ETreeNode(ETreeNode.DATA3D, "Boost", new TableNodeMetaData(Double.parseDouble(UtecProperties.getProperties("utec.boostMapMin")[0]), Double.parseDouble(UtecProperties.getProperties("utec.boostMapMax")[0]), ignored, false, "Boost" ));
root.add(fuel);
root.add(timing);
root.add(boost);
this.theTEL.TreeStructureChanged(root);
}
else if (cmd.equals("Save To Map #1")) {
@ -344,4 +361,9 @@ public class UtecTuningEntityImpl implements TuningEntity{
UtecInterface.openConnection();
}
}
public double[][] setTableData(String tableName, double[][] data) {
// TODO Auto-generated method stub
return null;
}
}